Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion CHANGELOG.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,25 @@ Chinese is the primary changelog and this file is its maintained English mirror.
explicitly unapproved for distribution without changing the XCFramework
Release's RootFS exclusion policy.

## v0.4.0-abi.11 (planned Stage1 maintenance prerelease)
## v0.4.0-abi.12 (planned Stage1 maintenance prerelease)

This is a compatibility maintenance release after `v0.4.0-abi.11`. It remains
a prerelease and is **not stable v0.4.0**.

- `third_party/ish` advances to `6b599fe7`. The internal Apple-platform
`wrlock_t` is now writer-preferring: once a writer queues, later readers
cannot barge indefinitely and starve code-dirty invalidation under sustained
guest read load.
- If `WNOWAIT` has observed a zombie but destructive `waitpid(WNOHANG)`
temporarily returns zero, the guest supervisor retries within the existing
cleanup deadline while the thread group finishes releasing resources rather
than incorrectly fail-closing the VM.
- Regression coverage now includes writer preference, deferred supervisor
reap, and platform-independent test access to lock state. The public C ABI
remains version 1, wire protocol remains v4, and Swift API is unchanged.
RootFS remains outside the Release.

## v0.4.0-abi.11 (published Stage1 maintenance prerelease)

This is a compatibility maintenance release after `v0.4.0-abi.10`. It remains
a prerelease and is **not stable v0.4.0**.
Expand Down
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,20 @@
`fs.tar.gz`,环境差异仍保留在外部证据中。CI 不上传制品,候选仍明确标记为未获分发
批准,不改变 XCFramework Release 的 RootFS 排除策略。

## v0.4.0-abi.11(计划中的 Stage1 维护预发布)
## v0.4.0-abi.12(计划中的 Stage1 维护预发布)

这是 `v0.4.0-abi.11` 之后的兼容性维护版本,仍是 prerelease,**不是稳定
v0.4.0**。

- `third_party/ish` 更新到 `6b599fe7`。Apple 平台的内部 `wrlock_t` 改为写者优先实现;
一旦写者排队,后到读者不能持续插队,避免代码脏页失效在持续 guest 读负载下饥饿。
- guest supervisor 在 `WNOWAIT` 已观察到 zombie、但 destructive
`waitpid(WNOHANG)` 暂时返回 0 时,会在原清理期限内重试,等待 thread group 完成资源
静止,而不是错误地 fail-close VM。
- 新增锁写者优先、supervisor 延迟 reap 与平台无关测试访问的回归覆盖。公开 C ABI 仍为
1,wire protocol 仍为 v4,Swift API 不变;RootFS 不进入 Release。

## v0.4.0-abi.11(已发布的 Stage1 维护预发布)

这是 `v0.4.0-abi.10` 之后的兼容性维护版本,仍是 prerelease,**不是稳定
v0.4.0**。
Expand Down
27 changes: 13 additions & 14 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ and simulator slices are arm64.

## Current phase: native ABI transition

The default branch has published `v0.4.0-abi.10` and is preparing the compatible
maintenance prerelease `v0.4.0-abi.11`. Both belong to the Stage1 **native ABI
The default branch has published `v0.4.0-abi.11` and is preparing the compatible
maintenance prerelease `v0.4.0-abi.12`. Both belong to the Stage1 **native ABI
transition**. Neither is stable `v0.4.0` or the complete v0.4 Swift API. Keep
these four version surfaces distinct:

| Surface | Current `v0.4.0-abi.10` | Planned `v0.4.0-abi.11` |
| Surface | Current `v0.4.0-abi.11` | Planned `v0.4.0-abi.12` |
| --- | --- | --- |
| Public C ABI | `ISH_EMBED_ABI_VERSION == 1`; atomic rename, finite-stdin deadlines, per-call stdin timeouts, and forced-teardown lifetime fixes are public | Still ABI 1; only the internal destructive-wait/reap boundary changes |
| Public C ABI | `ISH_EMBED_ABI_VERSION == 1`; forced-teardown and destructive-wait/reap lifetime fixes are public | Still ABI 1; only the internal Apple rwlock and deferred supervisor reap change |
| Internal wire protocol | exact-match v4 between host and embedded supervisor | still v4; this is not the public C ABI version |
| `Package.swift` | pins the public `v0.4.0-abi.10` URL/checksum | the release transaction creates a manifest-only release commit pinned to the maintenance binary |
| `Package.swift` | pins the public `v0.4.0-abi.11` URL/checksum | the release transaction creates a manifest-only release commit pinned to the maintenance binary |
| Swift source | remains v0.3.3-ABI compatible and includes typed rename plus per-call stdin timeouts | unchanged |

Stage1 native code adds session retain/release, a joinable kernel thread,
Expand Down Expand Up @@ -90,15 +90,15 @@ gives those narrow differences independent PRs, CI, and an exact gitlink, making
PocketRoot builds and releases reproducible. We do not directly rewrite somebody
else's local upstream repository; generally useful fixes can still be contributed
to [iSH upstream](https://github.com/ish-app/ish), while the fork carries project
gates until upstream accepts and releases them. The current `v0.4.0-abi.11`
gates until upstream accepts and releases them. The current `v0.4.0-abi.12`
source change includes neither RootFS content nor any prebuilt XCFramework/guest
binary; binaries may be produced and published only by a later release
transaction after its gates pass.

## Installation status

`v0.4.0-abi.10` is public and [`Package.swift`](Package.swift) currently pins it.
Until `v0.4.0-abi.11` is published, the manifest keeps pointing at that verified
`v0.4.0-abi.11` is public and [`Package.swift`](Package.swift) currently pins it.
Until `v0.4.0-abi.12` is published, the manifest keeps pointing at that verified
asset instead of advertising a future 404 URL. Use Xcode's
**File → Add Package Dependencies…** with:

Expand All @@ -110,12 +110,11 @@ Select a version whose tag, `libIshKernel.xcframework.zip`, Corresponding Source
and manifest URL/checksum all match. Consumer projects do not need Meson, Zig,
or LLVM.

`v0.4.0-abi.10` provides guest-atomic rename without a shell, bounded stdin
deadlines, per-call write/close timeouts, and lifetime fixes between forced
guest-task teardown and interval timers, shared fds, blocking syscalls, and
native output workers. `v0.4.0-abi.11` delays destructive waits until the full
thread group is quiescent, preventing sequential guest startup from reusing
runtime resources that the previous process still owns. It does not
`v0.4.0-abi.11` provides guest-atomic rename without a shell, bounded stdin
deadlines, per-call write/close timeouts, forced guest-task teardown, and delays
destructive waits until the full thread group is quiescent. `v0.4.0-abi.12`
further prevents writer starvation in the Apple-platform rwlock and lets the
supervisor boundedly wait for destructive reap after observing a zombie. It does not
implement a native Agent Loop or
install Codex CLI in the app.
Node.js/npm remain optional choices of the RootFS/guest package-management flow,
Expand Down
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ RootFS 安装、产品级命令策略、Swift Concurrency 隔离和界面。项

## 当前阶段:Native ABI 过渡

当前默认分支已发布 `v0.4.0-abi.10`,正在准备兼容性维护预发布
`v0.4.0-abi.11`。它们都属于 **Stage1 native ABI 过渡**,不是稳定 `v0.4.0`,
当前默认分支已发布 `v0.4.0-abi.11`,正在准备兼容性维护预发布
`v0.4.0-abi.12`。它们都属于 **Stage1 native ABI 过渡**,不是稳定 `v0.4.0`,
也不是完整 v0.4 Swift API。请同时区分下面四个版本面:

| 版本面 | 当前 `v0.4.0-abi.10` | 计划中的 `v0.4.0-abi.11` |
| 版本面 | 当前 `v0.4.0-abi.11` | 计划中的 `v0.4.0-abi.12` |
| --- | --- | --- |
| 公开 C ABI | `ISH_EMBED_ABI_VERSION == 1`;原子 rename、有限 stdin deadline、单次 stdin timeout 与强制 teardown 生命周期修复已发布 | 仍为 ABI 1;只收紧内部 destructive wait/reap 边界 |
| 公开 C ABI | `ISH_EMBED_ABI_VERSION == 1`;强制 teardown 与 destructive wait/reap 生命周期修复已发布 | 仍为 ABI 1;只收紧 Apple 内部读写锁与 supervisor 延迟 reap |
| 内部 wire protocol | host 与内嵌 supervisor 精确匹配 v4 | 仍为 v4;它不是公开 C ABI 版本 |
| `Package.swift` | 固定已公开的 `v0.4.0-abi.10` URL/checksum | 发布事务生成只改 manifest 的 release commit,固定到维护二进制 |
| `Package.swift` | 固定已公开的 `v0.4.0-abi.11` URL/checksum | 发布事务生成只改 manifest 的 release commit,固定到维护二进制 |
| Swift 源 | 保持 v0.3.3 ABI 兼容,已提供类型化 rename 与单次 stdin timeout | 不变 |

Stage1 的 native runtime 已加入 session retain/release、可等待 kernel 线程、soft-halt、
Expand Down Expand Up @@ -69,13 +69,13 @@ JIT 脏页一致性必须修改模拟器核心,无法只在 outer package 或
窄差异拥有独立 PR、CI 和精确 gitlink,PocketRoot 的构建与发布也因此可复现。我们不会在
本地直接改写别人维护的上游仓库;适合通用化的修复仍可回馈
[iSH upstream](https://github.com/ish-app/ish),但在上游接受并发布前由 fork 承担项目门禁。
当前 `v0.4.0-abi.11` 源码变更不纳入 RootFS,也不提交任何预构建
当前 `v0.4.0-abi.12` 源码变更不纳入 RootFS,也不提交任何预构建
XCFramework/guest binary;二进制只能在后续发布事务通过后生成和发布。

## 安装状态

`v0.4.0-abi.10` 已公开且当前 [`Package.swift`](Package.swift) 固定到它。
`v0.4.0-abi.11` 发布前,manifest 继续指向这个已验证的资产,不会提前引用 404 URL。
`v0.4.0-abi.11` 已公开且当前 [`Package.swift`](Package.swift) 固定到它。
`v0.4.0-abi.12` 发布前,manifest 继续指向这个已验证的资产,不会提前引用 404 URL。
在 Xcode 的 **File → Add Package Dependencies…** 中使用:

```text
Expand All @@ -85,11 +85,10 @@ https://github.com/jacklv-coder/ish-arm64-pkg
请选择明确包含 `libIshKernel.xcframework.zip`、对应源码归档,并且 manifest URL/checksum
与同一标签匹配的版本。业务工程不需要安装 Meson、Zig 或 LLVM。

`v0.4.0-abi.10` 已提供无 shell 的 guest 原子重命名、有界 stdin deadline、单次
write/close timeout,以及强制 guest task teardown 与 interval timer、共享 fd、阻塞
syscall 和 native output worker 之间的生命周期修复。`v0.4.0-abi.11` 会让破坏性 wait
在完整 thread group 静止后才发布进程退出,避免连续启动 guest process 时复用尚未释放的
runtime 资源。它不实现原生
`v0.4.0-abi.11` 已提供无 shell 的 guest 原子重命名、有界 stdin deadline、单次
write/close timeout、强制 guest task teardown,并让破坏性 wait 在完整 thread group
静止后才发布进程退出。`v0.4.0-abi.12` 进一步避免 Apple 平台读写锁的写者饥饿,并允许
supervisor 在已观察 zombie 后有界等待 destructive reap 真正可用。它不实现原生
Agent Loop,也不会
在 App 内安装 Codex CLI。Node.js/npm 如有需要仍由
RootFS/guest 包管理流程选择,不属于 runtime 的强制依赖。
Expand Down
11 changes: 6 additions & 5 deletions c-tests/dirty_page_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -878,11 +878,12 @@ struct drain_context {

static void confirm_dirty_reader_would_block(struct asbestos *asbestos,
pthread_mutex_t *mutex, pthread_cond_t *cond, bool *confirmed) {
// Probe the same underlying rwlock immediately before entering the
// production invalidation path. The compiler writer is already held, so
// EBUSY proves this worker has reached the lock and its next blocking read
// cannot pass until the stale block has been published.
assert(pthread_rwlock_tryrdlock(&asbestos->dirty_coherence_lock.l) == EBUSY);
// Observe only the wrlock API's implementation-independent state before
// entering the production invalidation path. The compiler writer is
// already held, so this worker's next blocking read cannot pass until the
// stale block has been published. Do not reach into the platform-specific
// pthread/custom lock representation here.
assert(asbestos->dirty_coherence_lock.val == -1);
assert(pthread_mutex_lock(mutex) == 0);
*confirmed = true;
assert(pthread_cond_signal(cond) == 0);
Expand Down
53 changes: 52 additions & 1 deletion c-tests/supervisor_stdin_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,7 @@ struct waitpid_event {
static struct waitpid_event test_waitpid_events[4];
static size_t test_waitpid_event_count;
static size_t test_waitpid_event_index;
static size_t test_waitpid_deferred_count;

static int test_waitid(idtype_t idtype, id_t id, siginfo_t *info,
int options) {
Expand Down Expand Up @@ -923,9 +924,14 @@ static pid_t test_waitpid(pid_t requested, int *status, int options) {
CHECK(options == WNOHANG);
CHECK(test_waitpid_event_index < test_waitpid_event_count);
struct waitpid_event event =
test_waitpid_events[test_waitpid_event_index++];
test_waitpid_events[test_waitpid_event_index];
CHECK(requested == event.pid);
CHECK(event.pid > 0);
if (test_waitpid_deferred_count > 0) {
test_waitpid_deferred_count--;
return 0;
}
test_waitpid_event_index++;
if (event.pid > 0 && status) *status = event.status;
return event.pid;
}
Expand Down Expand Up @@ -963,6 +969,7 @@ static void reset_process_hooks(void) {
ishsv_test_tcgetpgrp_hook = NULL;
test_waitpid_event_count = 0;
test_waitpid_event_index = 0;
test_waitpid_deferred_count = 0;
test_kill_count = 0;
test_foreground_pgid = 0;
g_instance_fail_closed = 0;
Expand All @@ -971,6 +978,49 @@ static void reset_process_hooks(void) {
#endif
}

/* WNOWAIT may observe the leader zombie before the embedded kernel permits a
* destructive reap: the final guest host pthread can still own shared task or
* address-space state. The supervisor must keep the numeric identity pinned
* and retry within its deadline, not fail-close the complete VM. */
static void test_observed_zombie_waits_for_thread_group_quiescence(void) {
const pid_t leader_pid = 4050;
memset(g_sessions, 0, sizeof(g_sessions));
reset_process_hooks();
ishsv_test_waitid_hook = test_waitid;
ishsv_test_waitpid_hook = test_waitpid;
ishsv_test_kill_hook = test_kill;

struct session *s = &g_sessions[0];
s->in_use = 1;
s->id = 800;
s->pid = leader_pid;
s->pgid = leader_pid;
s->pgid_validated = 1;
s->stdin_fd = -1;
s->stdout_fd = -1;
s->stderr_fd = -1;

const struct waitpid_event events[] = {
{leader_pid, 9 << 8},
{0, 0},
};
set_waitpid_events(events, sizeof(events) / sizeof(events[0]));
test_waitpid_deferred_count = 3;

reap_children_until(monotonic_ms() + 1000u);

CHECK(!g_instance_fail_closed);
CHECK(test_waitpid_deferred_count == 0);
CHECK(s->reaped && s->pid == 0 && s->pgid == 0 &&
!s->pgid_validated && s->exit_code == 9);
CHECK(test_kill_count == 1);
CHECK(test_kill_pids[0] == -leader_pid);
CHECK(test_kill_signals[0] == SIGKILL);

free_session(s);
reset_process_hooks();
}

static void test_host_build_requires_hook_for_instance_cleanup(void) {
reset_process_hooks();
errno = 0;
Expand Down Expand Up @@ -1513,6 +1563,7 @@ int main(void) {
test_host_build_requires_hook_for_instance_cleanup();
test_incomplete_shutdown_is_not_acknowledged();
test_cleanup_failures_do_not_report_success();
test_observed_zombie_waits_for_thread_group_quiescence();
test_reaped_pid_is_not_reused_as_session_identity();
test_tty_foreground_close_terminates_complete_session();
test_reaped_leader_cannot_leave_background_group_running();
Expand Down
10 changes: 5 additions & 5 deletions docs/README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ primary language; the English mirrors support collaboration and release review.
authoritative. Stage1 uses exact-match v4 between host and embedded supervisor.
3. **Swift source and manifest binary**: Stage1 Swift remains v0.3.3-ABI
compatible and does not call retain/release. The manifest currently pins the
public `v0.4.0-abi.10`; the release transaction moves it to the
`v0.4.0-abi.11` maintenance binary only after those assets are public and
public `v0.4.0-abi.11`; the release transaction moves it to the
`v0.4.0-abi.12` maintenance binary only after those assets are public and
verified.
4. **RootFS and PocketRoot**: RootFS is an independent asset and PocketRoot is
the product layer. Neither is completed automatically by a runtime PR or Release.

`v0.4.0-abi.10` and its `v0.4.0-abi.11` maintenance release are native-first
`v0.4.0-abi.11` and its `v0.4.0-abi.12` maintenance release are native-first
transition prereleases, not stable v0.4. The complete Swift lifecycle, typed
statuses, Terminal callback queue, and VT parser changes belong to Stage2.

Expand All @@ -44,7 +44,7 @@ statuses, Terminal callback queue, and VT parser changes belong to Stage2.
| [Architecture and lifecycle](architecture.en.md) | How is the runtime implemented? How do ABI 1 and wire v4 differ? |
| [Testing and acceptance](testing.en.md) | What do native, sanitizer, Swift/iOS 18, documentation, and supply-chain gates prove? |
| [Troubleshooting](troubleshooting.en.md) | Where should boot, link, protocol, output, shutdown, or release diagnosis start? |
| [Release transaction](releasing.en.md) | Why does the merged maintenance source still pin `v0.4.0-abi.10`, and when does it become `v0.4.0-abi.11`? |
| [Release transaction](releasing.en.md) | Why does the merged maintenance source still pin `v0.4.0-abi.11`, and when does it become `v0.4.0-abi.12`? |
| [Changelog](../CHANGELOG.en.md) | What is Stage1's scope and compatibility boundary? |

## Architecture on one page
Expand Down Expand Up @@ -99,7 +99,7 @@ fixes can still go upstream. See the
A direct-chain or RET target returns to the dispatcher only when it intersects
pending dirty code pages; data-only writes may keep chaining.
- RootFS is outside the package/Release and must not enter Corresponding Source.
- The current `v0.4.0-abi.11` source change carries no RootFS or prebuilt binary;
- The current `v0.4.0-abi.12` source change carries no RootFS or prebuilt binary;
a later release transaction must produce the XCFramework.

## Authoritative sources
Expand Down
Loading
Loading