源码索引 / CURRENT IMPLEMENTATION
guest/runtime.c
121 行 · 构建时读取的实际文件,不是讲解用伪代码。
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define EXPORT(name) __attribute__((export_name(name)))
#define MAX_MESSAGE (1 << 20)
__attribute__((import_module("spine"), import_name("call")))
int32_t host_call(const char *request, int32_t size, char *out, int32_t capacity);
__attribute__((import_module("spine"), import_name("prepare")))
uint32_t host_prepare(const char *request, int32_t size);
__attribute__((import_module("spine"), import_name("resolve")))
int32_t host_resolve(uint32_t id, const char *request, int32_t size, char *out, int32_t capacity);
// Python string → Host JSON request → Python bytes. Buffer lives only for this call.
static PyObject *python_call(PyObject *self, PyObject *args) {
const char *request;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "s#", &request, &size)) return NULL;
if (size > MAX_MESSAGE) { PyErr_SetString(PyExc_ValueError, "tool request exceeds 1 MiB"); return NULL; }
char *buffer = malloc(MAX_MESSAGE);
if (!buffer) return PyErr_NoMemory();
int32_t n = host_call(request, (int32_t)size, buffer, MAX_MESSAGE);
PyObject *result = NULL;
if (n < 0 || n > MAX_MESSAGE) PyErr_SetString(PyExc_RuntimeError, "Host tool response exceeds buffer or ABI bounds");
else result = PyBytes_FromStringAndSize(buffer, n);
free(buffer);
return result;
}
static PyObject *python_prepare(PyObject *self, PyObject *args) {
const char *request;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "s#", &request, &size)) return NULL;
if (size > MAX_MESSAGE) return PyLong_FromUnsignedLong(0);
return PyLong_FromUnsignedLong(host_prepare(request, (int32_t)size));
}
static PyObject *python_resolve(PyObject *self, PyObject *args) {
unsigned int id;
const char *request;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Is#", &id, &request, &size)) return NULL;
if (size > MAX_MESSAGE) { PyErr_SetString(PyExc_ValueError, "tool request exceeds 1 MiB"); return NULL; }
char *buffer = malloc(MAX_MESSAGE);
if (!buffer) return PyErr_NoMemory();
int32_t n = host_resolve(id, request, (int32_t)size, buffer, MAX_MESSAGE);
PyObject *result = NULL;
if (n < 0 || n > MAX_MESSAGE) PyErr_SetString(PyExc_RuntimeError, "Host tool response exceeds buffer or ABI bounds");
else result = PyBytes_FromStringAndSize(buffer, n);
free(buffer);
return result;
}
static PyMethodDef methods[] = {
{"call", python_call, METH_VARARGS, "Call a registered Host tool."},
{"prepare", python_prepare, METH_VARARGS, "Start an allowed read, returning a run-local handle."},
{"resolve", python_resolve, METH_VARARGS, "Consume a read at its original call position."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef module = {PyModuleDef_HEAD_INIT, "_spine", NULL, -1, methods};
static PyObject *init_spine(void) { return PyModule_Create(&module); }
static PyObject *execute_fn, *prefix_begin_fn, *prefix_feed_fn;
EXPORT("init") int32_t init(void) {
if (PyImport_AppendInittab("_spine", init_spine) != 0) return -1;
PyConfig config;
PyConfig_InitIsolatedConfig(&config);
config.site_import = 0;
config.write_bytecode = 0;
config.module_search_paths_set = 1;
PyStatus status = PyWideStringList_Append(&config.module_search_paths, L"/usr/lib/python3.14");
if (!PyStatus_Exception(status)) status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
fprintf(stderr, "CPython init: %s\n", status.err_msg ? status.err_msg : "unknown error");
PyConfig_Clear(&config);
return -1;
}
PyConfig_Clear(&config);
PyObject *bootstrap = PyImport_ImportModule("spine_bootstrap");
if (!bootstrap) { PyErr_Print(); return -1; }
execute_fn = PyObject_GetAttrString(bootstrap, "execute");
prefix_begin_fn = PyObject_GetAttrString(bootstrap, "prefix_begin");
prefix_feed_fn = PyObject_GetAttrString(bootstrap, "prefix_feed");
Py_DECREF(bootstrap);
if (!execute_fn || !prefix_begin_fn || !prefix_feed_fn) { PyErr_Print(); return -1; }
return 0;
}
// Prefix calls only parse received source and issue eligible reads, never execute it.
static int32_t prefix_step(PyObject *fn, const char *data, int32_t size) {
PyObject *result = PyObject_CallFunction(fn, "s#", data, (Py_ssize_t)size);
if (!result) { PyErr_Print(); return -1; }
Py_DECREF(result);
return 0;
}
EXPORT("prefix_begin") int32_t prefix_begin(const char *data, int32_t size) {
return prefix_step(prefix_begin_fn, data, size);
}
EXPORT("prefix_feed") int32_t prefix_feed(const char *data, int32_t size) {
return prefix_step(prefix_feed_fn, data, size);
}
EXPORT("alloc") void *alloc(uint32_t size) { return malloc(size); }
EXPORT("release") void release(void *ptr) { free(ptr); }
// Caller owns returned malloc buffer; upper 32 bits length, lower 32 bits pointer.
EXPORT("execute") uint64_t execute(const char *request, int32_t size) {
PyObject *result = PyObject_CallFunction(execute_fn, "s#", request, (Py_ssize_t)size);
if (!result) { PyErr_Print(); return 0; }
char *data;
Py_ssize_t length;
if (PyBytes_AsStringAndSize(result, &data, &length) < 0) { Py_DECREF(result); PyErr_Print(); return 0; }
char *copy = malloc(length);
if (!copy) { Py_DECREF(result); return 0; }
memcpy(copy, data, length);
Py_DECREF(result);
return ((uint64_t)(uint32_t)length << 32) | (uint32_t)(uintptr_t)copy;
}