文章

用户连接

晚上了,不太想干接下来该干的整理工作流脚本的活,写点字吧。

卡皮巴拉,或者说它所基于的那个版本的Demikernel,其协议栈抽象是一个自底而上层层嵌套的结构。每一层的协议栈称之为一个老哥(peer)。协议栈结构体包含了一个IP老哥,IP老哥结构体包含了一个TCP老哥和一个UDP老哥。卡皮巴拉则更进一步,TCP老哥当中包含了一个TCP迁移老哥。

写到这个去看了一眼最新版本的Demikernel。好家伙全给改完了,直接变成了协议栈自顶而下的层层嵌套结构了。

于是乎,如果想要兼容用户应用自定义的连接抽象的话,自然而然的设计便是再引入一层新的更上层的老哥,即用户连接老哥,由TCP迁移老哥包含。

写到这里又意识到,合理的设计应该是由TCP老哥来包含用户连接老哥。怎么回事还能不能干了(摔

如下面会写到的,目前的用户连接老哥更接近于「用户连接迁移老哥」,只有TCP迁移老哥会与之交互。考虑到后面会提到的技术困难(以及工期),估计TCP老哥应该始终都不会与之交互了,所以……就这样吧。

这为前面日志里提到的(提到了吗?)共享状态相关的迷思给出了清楚的答案。用户连接老哥属于协议栈的一部分,在程序创立阶段就由用户应用交给卡皮巴拉掌管,理应从此与用户应用再无关联。

以用户应用陷入事件循环的「系统调用」,即卡皮巴拉中的libos.wait_any(..),或是POXIS垫片转接后的epoll_wait(..)为分界线,任何在调用中发生在「运行时中」的逻辑为运行时侧逻辑,任何在调用返回到下次调用之间发生在「用户应用中」的逻辑为应用侧逻辑。两者黑白分明,不共享任何可变状态。(除了运行时对象libos,以及与其对应的「系统内核」的概念。)

用户连接老哥属于运行时侧逻辑,因此归属于卡皮巴拉运行时。虽然用户连接老哥的逻辑由用户实现,其功能也与用户实现的其余代码(即应用测逻辑)息息相关(比如实现了TLS的用户连接老哥,与其一同的用户应用一定是被设计为与TLS层的接口交互的),但是它被送进了运行时,从此以后就不能再被用户侧逻辑访问了。

这样行吗?这样不行。


用户连接的完整支持是会对卡皮巴拉运行时的功能语义产生大幅度影响的。

一方面,需要给用户提供用户连接特定的接口。比如TCP客户端的connect(假设TCP是用户连接的话),比如TLS的设置身份证书。

另一方面,事件循环接口返回的事件也由用户连接控制。比如TCP的事件是基于管道概念的,只有管道又送到了数据流就可以随时送上去;而HTTP的事件是基于帧的,一个HTTP请求要全都收齐了才一次性送上去。

这两方面的事情,也许能做也许做不成,但是我肯定都是没时间做的。

于是我们采用一种折中且脏乱的方案:共享用户连接老哥。

运行时的接口和返回的事件保持TCP层不变。需要多的接口用户应用直接找用户连接老哥。收到了事件用户也去直接找用户连接老哥来翻译一下。

如此同时,运行时侧逻辑也找用户连接老哥,处理迁入迁出相关事宜。

由于我们要支持的用户应用都是用C写的,共享对象也就变得(看起来)不那么让人情感上难以接受了,这能算是塞翁失马吗(

不知道还有没有什么要写的,今天先到这里再想起来再说吧。

本文由作者按照 CC BY 4.0 进行授权