模块契约Core API
错误对象
错误是引用计数的不可变对象:Create/Build 族返回拥有引用,Ref/Free 配对;Wrap 建立原因链并增加原因的引用。
错误访问器
访问器全部接受空指针:消息返回 "(no error)" 或占位值,其余返回零/NONE——便于对 xrtGetError() 的空结果直接调用。
线程错误上下文
每个线程有独立的错误槽。成功调用不会清除已有错误;判断前按需 xrtClearError()。
Windows 动态嵌入的最终线程存储退役
bool xrtRuntimeRetireThreadStorage(void) 退役当前 XRT 实例注册的内部 FLS/TLS 槽,包括堆缓存、默认错误、默认临时 arena、TinyCC 随机/故障注入状态、 Future 通知与线程/协程借用槽。清理顺序是 payload → error → heap → borrowed, 不依赖惰性初始化的先后。它不会禁用正常运行期间的线程缓存。
宿主必须先关闭所有调用/回调入口,等待 XRT 工作结束,释放外部持有对象、任务、 动态线程键等资源,并在各自线程清理动态键、解绑执行上下文。宿主线程和 Fiber 可以保持存活,但不得再进入该实例,也不得与退役并发退出或销毁 Fiber。 之后,在代码和分配器仍驻留时、DllMain 和加载器锁之外调用此接口,成功返回后 才可卸载代码。FLS 槽释放会同步析构所有 Fiber 的非空值;先保留错误和堆的依赖, 最后移除保护槽。不会在持有注册表锁时执行这些析构。
这是终态操作,不是 reset:成功后重复调用返回 true;失败可能已经完成部分清理, 只能保持代码驻留并重试,不能恢复业务或调用 XRT 错误接口。新槽注册被关闭, 重入/并发退役返回 false。本接口自身不分配内存、不访问错误 TLS。 非 Windows 平台当前返回 false 且不改变状态;不宣称支持 POSIX 共享库退役。
此接口只消除内部线程存储的代码引用,不收集对象图、不判定外部引用是否已经释放, 不清空中央堆 span 或其他模块级资源。对象和代码租约的正确性仍由宿主负责。
版本与公共宏
| 名称 | 含义 |
|---|---|
XRT_VERSION_MAJOR | 主版本号 |
XRT_VERSION_MINOR | 次版本号 |
XRT_VERSION_PATCH | 修订版本号 |
XRT_VERSION_TEXT | 零结尾版本字符串 |
XRT_NPOS | size_t 查找接口共用的未找到值 |
XRT_API | 静态库、导出库和导入库共用的符号规则 |
XRT_EXTERN_C_BEGIN / XRT_EXTERN_C_END | C++ 调用时使用 C 链接 |
基础类型
int8、uint8、int16、uint16、int32、uint32、int64 和 uint64 固定宽度。ptr 是可写无类型指针,str / cstr 是可写和只读 UTF-8 零结尾字符串,bytes / cbytes 是可写和只读字节指针。
xtime 是有符号 64 位 公元 UTC 毫秒,可直接用作 FFI 和跨模块时间标量。 单调时钟不使用该类型,避免把持续时间误当成绝对日期。
资源边界
xrtresourcelimits 为解析器、压缩器、归档器和其他可能放大输入的模块提供统一边界:
| 字段 | 含义 |
|---|---|
iMaxInputBytes | 最多消费的输入字节数 |
iMaxOutputBytes | 最多生成的输出字节数 |
iMaxItemBytes | 单个条目、字段或文件的最大字节数 |
iMaxEntries | 最大条目数 |
iMaxNodes | 最大语法树或对象节点数 |
iMaxDepth | 最大嵌套深度 |
iMaxCompressionRatio | 最大输出输入比;输入为零时由具体模块拒绝非空输出 |
iFlags | 显式允许符号链接、硬链接、设备文件或外部实体 |
允许危险资源必须显式设置 XRT_RESOURCE_ALLOW_SYMLINKS、 XRT_RESOURCE_ALLOW_HARDLINKS、XRT_RESOURCE_ALLOW_DEVICE_FILES 或 XRT_RESOURCE_ALLOW_EXTERNAL_ENTITIES。具体模块只解释与自身相关的标志。
借用视图
两个 View 都只借用内存,不拥有数据,也不要求末尾补零。Size == 0 时 Data == NULL 合法。XRT_BYTES_INIT / XRT_STR_INIT 用于静态聚合初始化, XRT_BYTES_LITERAL / XRT_STR_LITERAL 用于赋值和函数实参。
这四个宏按 sizeof(array) - 1 计长,只能接受编译期数组或字符串字面量, 不能用于指针:
引用计数
对象把初始计数设为一。Retain 原子加一并返回新值,Release 原子减一并 返回新值;返回零的线程负责析构对象。空指针、非正计数、复活已经归零的对象、 释放非正计数及递增 INT32_MAX 都返回 -1,且不修改计数。
这两个通用函数只保护计数,不发布对象字段、不加入 ownership freeze 域,也不 替代对象自己的并发契约。对象在交给其他线程前仍必须通过锁、原子发布或 XRT 已声明的线程安全 API 建立 happens-before。只有实际作为 ownership graph 节点计数的独立原子更新才使用 xrtOwnershipRefRetain/Release;涉及字段、回调 或析构的转换必须用一个外层 mutation scope 覆盖完整过程。
内存
全库动态内存统一走这些入口,因此 xrtSetAllocator 可以整体替换底层分配器。 At 变体(XRT_FEATURE_MEMORY_DEBUG 下提供)记录调用位置用于泄漏诊断,语义与对应基础函数一致。
结构快照与显式接管协议
xrtOwnershipSnapshotCreate/NodeCount/Node/Destroy 复用 Inspect 的同一物理图算法。 每个节点保存真实强计数、内部入边计数和可达性;不保有节点。准入回调先于该 节点的 Count/Trace,可在调用未知代码之前拒绝整个图。节点顺序是首次发现 顺序:先输入 anchor,再 internal slot,最后展开出边。重复物理身份只出现一次。 失败不修改输出;读取节点不重新扫描、不分配,销毁只释放快照记账。 调用方必须独立保持完整图静止及节点、回调代码有效,直到建立真正的保有引用。
xrtownershipadapterv1 是独立的生命周期协议,不扩展旧二函数 xrtownershipops 的内存布局。解析器须证明完整 mutation 参与与上下文能力,不能仅凭 Trace 存在 就认证。Hold/Drop 对应实际引用;Claim/Restore 以独占 token 隔离弱/raw 新准入, 允许已有合法强拥有者在 Finalize 后产生可检测的复活。Finalize 在 freeze 外运行, 其物理“已执行”状态跨撤销保留。重新判断根、检查新析构职责与 Clear 必须在同一 freeze 内完成;Clear 不能分配、失败、等待或运行用户代码。Finish 在 freeze 外 处理已准备的机械释放尾部,不得开始新的用户语义析构或发布已接管的 receiver。
XRT 提供普通 Value/backing、明确授权的对象/Handle 生命周期适配器,见 Value 文档;完整事务协调由上层实现。xrtErrorOwnershipAdapterV1 另外识别本实例的 不可变 Error/Cause DAG:文本内联拥有,Cause 只指向更早的错误,不存在回指语言 模块的边或用户回调。其 Clear 不修改不可变数据,真实 Cause 边保留到最后一次 Drop;外部错误别名因此不会反向保活模块。这不是 XRT 自动 GC,也不证明任意 原生上下文或语言模块可以回收。
析构前语义准备
xrtownershippreparationv1 与生命周期表是两个独立、不可变的描述符;Adapter 必须精确指向同一生命周期表,不能扩展旧表或把未知描述符降级为空准备职责。 Ready 在 freeze 内只读检查,Prepare 在 freeze/mutation 外运行,可正常通知 已受理的回调。READY 后必须重建完整物理图,再决定下一项准备或析构;通知可能 增加新节点或外部引用,不能继续使用通知前的可达性。每一次对象 Finalize 后也须 重新检查,防止析构新建资源后提前析构其捕获对象。
BUSY 不允许本次准备调用产生语义回调或改变拥有边,可非阻塞地尝试其他依赖。 FAILED 是显式失败,即使没有诊断对象也不能当作成功。上层应区分快照/准入失败 和语义调用失败;已经发生的通知和物理析构职责不能因撤销、分配失败或重试而重放。
旧版资产决策
新版保留旧 xrt.h / base.h 中简短类型名称、毫秒 xtime、原子引用及 无需复杂对象即可使用的风格,并补齐固定宽度、只读指针和显式借用 View。 旧 test_base.h 的有效引用边界由核心单元测试和并发测试承接;可变全局状态、 隐式字符串所有权和初始化引用计数被明确退役。
完整范例位于 examples/core/(error / memory / reference / version_limits / allocator_tour)与 examples/error/tour。
内存范围
xrtMemRangeValid() 验证半开范围 [Data, Data + Size) 的起点和末地址计算;空范围允许空指针。xrtMemRangesOverlap() 使用地址差判断两个非空范围是否重叠,不计算可能回绕的末地址。调用重叠判断前,调用方应先分别验证两个范围。
这两个函数是头文件内联的零分配基础能力,适合协议解析器、视图类型和扩展库统一执行边界检查。
设计契约
所有 XRT 动态内存最终经过同一个进程级底层分配器。默认实现使用 C 运行库分配器;嵌入方可以在第一次 XRT 分配之前替换它。首次原始分配后分配器冻结,避免同一地址由不同分配器交叉释放。安装、读取和首次分配使用同一短临界区,并发发生时只有一个顺序获胜,不会观察到撕裂配置。
xrtMalloc(0) 和 xrtCalloc(0, n) 仍返回一块可释放的非空内存。xrtRealloc(p, 0) 释放 p 并返回 NULL。所有返回地址至少按 16 字节对齐;该保证不依赖平台 C 分配器在 32 位环境下的最低对齐值。
小于等于 1024 字节的分配沿用旧版 16 字节尺寸类与 span 复用,并由每个原生 线程惰性缓存少量空闲块。缓存按批从中央链补给,超过上限时批量归还;线程退出 时通过 FLS 或 pthread key 析构完整归还。外部 C 线程无需先附加到 XRT。TLS 资源或缓存元数据申请失败只会退回中央链,不会让原本可完成的用户分配失败。 显式内存池的用户区始终从底层全局分配起点之后开始,因此首个池对象也不会与 可直接传给 xrtFree 的地址发生别名。
全局分配器
进程唯一底层分配器的安装、读取和全部派生入口。
引用计数与运行时信息
嵌入对象引用计数和版本、资源上限查询。
范例
完整范例位于 examples/core/memory/main.c。
旧版资产决策
新版保留旧 base.h / memglobal.h 已经验证的零大小处理、16 字节尺寸类、 同类原位 realloc、跨类数据保留、小块 span 复用、每线程缓存及批量中央链 交换。旧公开 xCore 分配器函数指针、线程对象内嵌缓存布局和必须显式 xrtUnit() 才能清理的状态被替换为不可见进程级堆与独立线程缓存;分配器 配置使用独立 API,模块不能直接改写全局函数指针。
旧 test_base.h 与 test_memglobal_core.h 的有效边界由 test_memory、 test_heap、test_heap_threads 和 OOM 回归承接,并新增并发分配器冻结、 32 位对齐、溢出原子失败、未附加原生线程、线程退出缓存归还和调试归属诊断。
设计契约
xerror 是不可变、可跨线程持有的结构化错误对象。错误由通用类别、稳定域、模块代码、系统代码、操作名、UTF-8 消息、可选数据和原因链组成。通用类别用于跨模块控制流,域与代码用于模块精确判断,消息只用于展示。
Core 错误 API 不依赖容器、字符串模块或 printf 运行时。需要结构化附加数据的模块应为 Data 定义稳定格式,或在自己的结果对象中保存详细字段,不能要求调用方解析展示消息。 动态消息格式化是独立的 error_format 便利模块,不增加最小 Core 的代码体积。
通用类别
XERR_ARGUMENT、XERR_TYPE、XERR_VALUE、XERR_RANGE:输入不符合契约。XERR_STATE:对象或运行时状态不允许当前操作。XERR_MEMORY:内存不足。XERR_IO、XERR_NOT_FOUND、XERR_EXISTS、XERR_PERMISSION:系统资源错误。XERR_AGAIN:当前无法推进,但对象仍有效,调用方可等待后重试。XERR_TIMEOUT、XERR_CANCELLED、XERR_CLOSED:等待终止或资源关闭原因。XERR_PROTOCOL、XERR_UNSUPPORTED、XERR_INTERNAL:协议、能力或内部不变量错误。
XERR_NONE 只表示没有错误,不能用于创建错误对象。
字段与原因链
xrtErrorKind、xrtErrorDomain、xrtErrorCode、xrtErrorSystemCode、xrtErrorOperation、xrtErrorMessage、xrtErrorData 和 xrtErrorCause 返回不可变字段。空错误指针返回零值或空字符串。
xrtErrorIs 沿原因链查找通用类别。xrtErrorFind 沿原因链精确匹配域和代码。两者返回借用指针,未找到时返回 NULL。
OOM 保证
参数、状态、范围和内存不足等核心错误使用静态不可变对象。即使自定义分配器 已经失败,xrtMalloc() 仍能无分配地设置 XERR_MEMORY,错误构造失败也 不会用第二次分配覆盖这个原因。
范例
结构化原因链范例位于 examples/core/error/main.c,动态消息范例位于 examples/core/error_format/main.c。
旧版资产决策
旧版只保存线程局部 UTF-8 字符串,并通过 bFree 把消息所有权交给错误槽; 模块只能依赖消息文本,上层宿主也无法稳定区分错误类别。新版保留线程隔离、 设置/读取/清除的简短手感和进程级观察回调,替换为不可变引用对象、稳定域与 代码、系统代码、操作、机器数据和原因链。
旧 test_base.h 的字符串错误、UTF-16/UTF-32 转换入口不进入核心错误层; 字符转换由 Charset 完成,模块直接构造 UTF-8 结构化错误。当前回归额外覆盖 错误深复制、原因查询、并发线程隔离、线程退出析构、协程执行上下文和 OOM 无分配报告。
附录:Core 并集函数
本文件的门禁并集包含 core 模块全部四个头(features/core/error/memory),因此下列内存、引用与版本函数在本文件同样成节;完整模块语境见 core.md 与 memory.md。
xseek类型
通用 IO 与文件游标共享的移动基准。
| 值 | 语义 |
|---|---|
XSEEK_START | 从文件起点 |
XSEEK_CURRENT | 从当前位置 |
XSEEK_END | 遍历结束 |
xrtresourcelimits类型
资源限额结构:限制输入/输出/单项字节数、条目数、节点数、深度与压缩比;iFlags 启用符号链接/硬链接/设备文件/外部实体的放行位。结构带 iSize/iVersion 前向兼容字段,未指定字段保持零值。
| 字段 | 类型 | 语义 |
|---|---|---|
iSize | uint32 | iSize |
iVersion | uint32 | iVersion |
iMaxInputBytes | uint64 | iMaxInputBytes |
iMaxOutputBytes | uint64 | iMaxOutputBytes |
iMaxItemBytes | uint64 | iMaxItemBytes |
iMaxEntries | uint64 | iMaxEntries |
iMaxNodes | uint64 | iMaxNodes |
iMaxDepth | uint32 | iMaxDepth |
iMaxCompressionRatio | uint32 | iMaxCompressionRatio |
iFlags | uint32 | iFlags |
iReserved | uint32 | iReserved |
xrtprogressflag类型
进度事件标志:TOTAL_KNOWN 表示总输入量已知,FINAL 表示本次事件为最后一次。
| 值 | 语义 |
|---|---|
XRT_PROGRESS_TOTAL_KNOWN | XRTPROGRESSTOTALKNOWN |
xrtprogress类型
长耗时流操作共用的进度事件(带 iSize/iVersion 前向兼容字段);回调仅在发起操作的线程内同步调用。
| 字段 | 类型 | 语义 |
|---|---|---|
iSize | uint32 | iSize |
iVersion | uint32 | iVersion |
iFlags | uint32 | iFlags |
iReserved | uint32 | iReserved |
iInputBytes | uint64 | iInputBytes |
iTotalInputBytes | uint64 | iTotalInputBytes |
iOutputBytes | uint64 | iOutputBytes |
xbytesview类型
字节视图只借用内存,不拥有数据,也不要求末尾补零。
| 字段 | 类型 | 语义 |
|---|---|---|
Data | cbytes | 数据 |
Size | size_t | 字节数 |
xstrview类型
字符串视图只借用字节,不拥有数据,也不要求末尾补零。
| 字段 | 类型 | 语义 |
|---|---|---|
Data | cstr | 数据 |
Size | size_t | 字节数 |
xtime类型
绝对时间使用 公元 UTC 毫秒;该标量也是 xlang time 类型的底层表示。 不透明句柄或别名;生命周期与所有权见各使用方 API 节。
xrtprogressproc类型
返回 false 请求取消。实现不得在回调返回后继续保存 pProgress 或 pUserData。 回调类型;参数与返回语义见签名及各使用方 API 节。
xrtVersion函数
返回当前 XRT 版本字符串。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
| 无 | — | — | 无参数 |
| 返回 | 含义 |
|---|---|
cstr | XRT_VERSION_TEXT 静态借用字符串,不得释放 |
xrtResourceLimitsInit函数
把资源边界初始化为适合处理不受信任输入的保守默认值。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pLimits | 输出 | 非空 | 接收清零后的保守默认边界 |
| 返回 | 含义 |
|---|---|
| 无 | 先清零整个结构再写默认值;零值字段表示不限制该项目 |
范例已编译验证
core/version_limits · 资源边界 · 初始化后按需收紧
printf("version=%s\n", xrtVersion());
xrtResourceLimitsInit(&Limits);
xrtRefRetain函数
原子增加引用计数并返回新值。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pCount | 输入/输出 | 非空、正计数 | 对象内嵌的 volatile int32 计数字段 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
> 0 | 新计数值 | — |
-1 | 空指针、非正计数或达到 INT32_MAX(溢出保护) | 计数不变,不设置错误 |
- 无 — 原语按返回值报告;调用方把
-1当失败处理
范例已编译验证
core/reference · 共享对象 · 第二持有者接管前先 Retain
if ( (pObject == NULL) || (xrtRefRetain(&pObject->RefCount) < 0) ) {
return NULL;
}
xrtRefRelease函数
原子减少引用计数并返回新值;返回零的线程负责析构。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pCount | 输入/输出 | 非空、正计数 | 对象内嵌计数字段 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
> 0 | 仍有其他持有者 | — |
0 | 调用方是最后持有者,执行析构 | — |
-1 | 空指针或非正计数(重复释放) | 计数不变,不设置错误 |
- 无 — 原语按返回值报告
范例已编译验证
core/reference · 析构判定 · 归零者释放对象
if ( (pObject != NULL) && (xrtRefRelease(&pObject->RefCount) == 0) ) {
xrtOwnershipRefRetain函数
在 ownership mutation 域中原子增加一个图可见引用计数。它只覆盖这一条原子 更新;如果引用变更还伴随 owning slot、状态位或链表变化,调用方必须改用覆盖 完整转换的 xrtOwnershipMutationBegin / xrtOwnershipScopeEnd。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pCount | 输入/输出 | 非空、正计数 | ownership graph 节点的计数字段 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
> 0 | 新计数值 | — |
-1 | 空指针、非正计数、达到 INT32_MAX 或准入失败 | 计数不变 |
- 计数边界仍只通过
-1报告;准入错误遵循 ownership scope 契约
范例已编译验证
core/reference · 引用管理 · 图节点使用显式准入版本
if ( xrtOwnershipRefRetain(&pLeaf->References) < 0 ) {
return NULL;
}
xrtOwnershipRefRelease函数
在 ownership mutation 域中原子减少一个图可见引用计数。返回零只表示调用方 取得最后引用;具有出边或析构回调的对象仍须把完整析构放入同一个外层 scope。
参数
| 参数 | 方向 | 约束 | 说明 |
|---|---|---|---|
pCount | 输入/输出 | 非空、正计数 | ownership graph 节点的计数字段 |
| 返回 | 含义 | 失败时状态 |
|---|---|---|
> 0 | 仍有其他持有者 | — |
0 | 调用方取得最后引用 | — |
-1 | 空指针、非正计数或准入失败 | 计数不变 |
- 计数边界仍只通过
-1报告;准入错误遵循 ownership scope 契约
范例已编译验证
core/reference · 析构判定 · 仅用于无其他图转换的计数更新
if ( xrtOwnershipRefRelease(&pLeaf->References) == 0 ) {
xrtFree(pLeaf);
}
xrtProgressReport函数
契约注释见公共头文件。
xrtOwnershipMutationBegin函数
契约注释见公共头文件。
xrtOwnershipFreezeTryBegin函数
契约注释见公共头文件。
xrtOwnershipScopeEnd函数
契约注释见公共头文件。
xrtOwnershipInspect函数
契约注释见公共头文件。
xrtOwnershipInspectReachable函数
契约注释见公共头文件。
xrtOwnershipSnapshotCreate函数
契约注释见公共头文件。
xrtOwnershipSnapshotNodeCount函数
契约注释见公共头文件。
xrtOwnershipSnapshotNode函数
契约注释见公共头文件。
xrtOwnershipSnapshotDestroy函数
契约注释见公共头文件。
xrtRuntimeRetireThreadStorage函数
契约注释见公共头文件。
常量索引常量
以下常量在本页所属头文件中定义,语义见公共头注释。
| 常量 | 说明 |
|---|---|
| XRT_API | 见头文件注释 |
| XRT_BYTES_INIT | 见头文件注释 |
| XRT_BYTES_LITERAL | 见头文件注释 |
| XRT_EXTERN_C_BEGIN | 见头文件注释 |
| XRT_EXTERN_C_END | 见头文件注释 |
| XRT_NPOS | 见头文件注释 |
| XRT_OWNERSHIP_PREPARE_BUSY | 见头文件注释 |
| XRT_OWNERSHIP_PREPARE_FAILED | 见头文件注释 |
| XRT_OWNERSHIP_PREPARE_READY | 见头文件注释 |
| XRT_PROGRESS_FINAL | 见头文件注释 |
| XRT_PROGRESS_TOTAL_KNOWN | 见头文件注释 |
| XRT_PROGRESS_VERSION | 见头文件注释 |
| XRT_RESOURCE_ALLOW_DEVICE_FILES | 见头文件注释 |
| XRT_RESOURCE_ALLOW_EXTERNAL_ENTITIES | 见头文件注释 |
| XRT_RESOURCE_ALLOW_HARDLINKS | 见头文件注释 |
| XRT_RESOURCE_ALLOW_SYMLINKS | 见头文件注释 |
| XRT_RESOURCE_LIMITS_VERSION | 见头文件注释 |
| XRT_STR_INIT | 见头文件注释 |
| XRT_STR_LITERAL | 见头文件注释 |
| XRT_VERSION_MAJOR | 见头文件注释 |
| XRT_VERSION_MINOR | 见头文件注释 |
| XRT_VERSION_PATCH | 见头文件注释 |
| XRT_VERSION_TEXT | 见头文件注释 |
| XSEEK_CURRENT | 见头文件注释 |
| XSEEK_END | 见头文件注释 |
| XSEEK_START | 见头文件注释 |