详细描述
以下描述示出了允许具有进程间通信能力的隔离进程的操作系统(OS)。所述OS隔离进程之间的隔离是静态可验证的。隔离进程的可执行指令可在编译时或运行时或两者验证。而且,此处所述了便于开发隔离进程之间的静态可验证进程间通信的一个或多个编程语言工具。
静态可验证进程是可在无需实际执行软件进程的指令的情况下分析其可执行指令的软件进程。分析确保进程不会以不允许的方式工作和/或干预其它进程或操作系统本身的操作。
此处所述的一个或多个实现采用编程语言工具来创建其中软件更可能良好地构建、程序行为更易于验证、且运行时故障可被容忍并缓和的环境。此处所述的一个或多个实现的一些特征包括(但不限于):
·数据在双向通道上交换,其中每一通道由正好两个端点组成。在任何时刻,每一通道端点为单个线程所有(即,为单个进程所有)。
·缓冲器和其它存储器数据结构由指针转移,而非通过复制包含在缓冲器和存储器数据结构中的数据。这些转移传递存储器块的所有权。
·通道通信由静态可验证通道契约管控,这些契约将消息、消息自变量类型和有效消息交互序列描述为类似于会话类型的有限状态机。
·通道端点可在通道上在消息中发送。因此,通信网络可动态发展。
·在通道上发送和接收不需要存储器分配。
·发送是无阻塞且无故障的。无阻塞意味着,发送不等待通信成功。无故障意味着通信最后总是成功。实现按以下定义对此达成:发送操作在不等待结果的情况下完成。(然而,“通道”可能会发生故障,这可当在通道上接收时观察到。)
示例性操作系统和编程工具
图1示出了支持静态可验证进程间通信软件隔离进程(SIP)以及对便于编程这样的静态可验证进程间通信SIP的编程工具的使用的示例性操作场景。
图1示出了在计算机120的存储器110中存储和/或执行的操作系统100和编程工具160。计算机120一般包括各种处理器可读介质(包括存储器110)。这样的介质可以是可由计算机120访问的任何可用介质,且包括易失性、非易失性介质、可移动和不可移动介质。
计算机120包括存储一组加载模块124的计算机存储设备122(例如,硬盘驱动器、RAID系统等)和工作存储器130(它是存储器110的一部分或与存储器110分开)。
工作存储器130也包括交换堆132,它是用于保存信息(诸如对工作存储器130中的位置的指针)的缓冲器。此处,交换堆可被称为“缓冲器”、“共享交换缓冲器”或与之等效的东西。堆可包括多个可寻址存储器块(如框134所示)。尽管交换堆132整体上可由多个处理器访问,但各个块一次为一个进程所有(当块在使用时)。然而,存储器块的所有权可与另一活动进程交换。因此,以此方式,交换堆132提供供SIP交换数据的机制。
如所述,操作系统100包括进程构造器150模块。进程构造器可以是操作系统100的内核的一部分。处理器构造器150根据一般被表现为存储在计算机存储中的加载模块的集合的组成组件的动态集构造计算机工作存储器中的进程。
在图1的示例中,进程构造器150构造存储在工作存储器130中的进程140。如此处所述,根据加载模块124构造进程140,加载模块124是进程的扩展组件编辑的进程组成组件的表现。
进程140具有进程清单142,它定义了进程140的内容、进程所许可的行为、以及进程的其它可能的属性。如此所述,进程清单142与其描述组成的进程(诸如进程140)直接相关联。
编程工具160包括模块和数据结构。采用这些,编程工具160帮助开发进程的人们用进程的所定义且受限的进程间通信创建静态变量和隔离进程。编程工具160通过使用在编译时、运行时或两者实施的强不变性来促进这种开发。以下在“验证”章节中讨论强不变性。
编程工具160提供静态分析工具来帮助编程员在无需耗时的测试和调试的情况下找到、更正和/或防止进程间通信错误。通过增加确定的静态预计算分析工具的有效性和适用性,编程工具160还增加了一个或一组编程员将产生没有进程间通信相关错误的一个或一组程序的可能性,并进一步减少了产生这样的一个或一组程序所需的测试和调试努力。
所述编程工具(例如,图1的编程工具160)采用便于开发员使用和创建SIP(如此处所述)的编程构造和方法。采用所述的编程工具,SIP通信可被静态验证。
软件隔离进程
在计算机科学领域,更具体地在操作系统领域,术语“软件进程”(或简称为“进程”)是公知的。应用程序通常由一个或多个进程组成。操作系统(OS)意识到并实际上可管理和监督运行在计算机上的一个或多个单独的进程。
此处描述了在允许和/或支持软件隔离进程(SIP)抽象模型的OS模型中操作一个或多个实现。SIP封装程序或系统,并提供信息隐藏、故障隔离和强接口。根据所述实现,SIP在OS和应用程序软件中贯串使用。
采用SIP,内核外的可执行代码在SIP中执行且通过强类型通信通道来通信。SIP是封闭的环境,它不允许数据共享或动态代码加载。SIP在多个方面与常规的OS进程不同。以下是SIP与常规OS进程不同的这样的方面的示例:
·SIP是封闭的对象空间而非地址空间。两个SIP不能同时访问一个对象。进程间的通信转移数据的排他所有权。
·SIP也是封闭的代码空间。进程不能动态加载或生成代码。
·SIP不依赖于存储器管理硬件来隔离,因此多个SIP可驻留在一物理或虚拟地址空间中。
·SIP之间的通信是通过双向、强类型、高阶通道。通道的类型描述其通信协议以及它所传输的值,这两方面都得到验证。
·创建SIP是不昂贵的,且SIP之间的通信造成较低的开销。其低成本使得使用SIP作为精细粒度隔离和扩展机制是实际的。
·SIP由操作系统创建和管理,因此在终端上,SIP的资源可被高效回收。
·SIP是独立的执行环境,甚至对具有不同数据布局、运行时系统和垃圾收集器而言也是如此。其它的安全语言系统支持一个执行环境。
此处为方便起见使用术语“软件隔离进程”即“SIP”。不旨在限制该概念的范围。实际上,该概念可用软件、硬件、固件或其组合来实现。
进程间通信
图2示出了便于进程间通信而没有不曾预料到的SIP之间的交互的示例性进程间通信(IPC)体系结构200。除允许进程之间的通信以外,示例性IPC体系结构200可允许进程与操作系统内核之间的通信。
采用示例性IPC体系结构200,SIP通过在通道上发送消息来排他地通信,通道是两个进程之间双向、行为类型连接。消息是“交换堆”(诸如以上图1中的交换堆132)中从发送进程传输到接收进程的值或消息块的带标签集合。通信由契约来定类型,契约指定消息的格式和沿通道的有效消息序列。
如图2所示,示例性IPC体系结构200实现在计算机202上,计算机202配备存储器210(例如,易失性、非易失性、可移动、不可移动等)。操作系统(212)被示为存储在存储器210中,且在计算机202上执行。
OS 212具有内核220。OS内核220包括进程间通信(IPC)促进器222。OS内核可构造一个或多个进程。图2例如示出了三个运行在存储器210中的活动进程(230、240和250)。
IPC促进器222促进活动进程(诸如进程230、240和250)之间的通信。尽管图2示出了OS内核220实现IPC促进器222,但其它实现可具有OS内核外的IPC促进器。如果这样,它们各自将与OS合作和/或协作工作。
存储器210也包括交换堆290,它具有多个存储器块292。交换堆290可由多个活动进程(诸如,进程230、240和250)访问。它提供供SIP交换数据的机制。
“Inter-Process Communications Employing Bi-directional Message Conduits(采用双向消息管道的进程间通信)”公开了关于示例性IPC体系结构200的附加细节,该体系结构适于此处描述的一个或多个实现。
交换堆
每一SIP维护其自己独立且私有的堆。SIP不彼此共享存储器。因此,当数据从一个SIP传递到另一SIP时,所传递的数据不是来自进程的私有堆的。相反,它来自用于保存可在进程之间移动的数据的单独的堆。该单独的堆是交换堆,诸如图1中所示的交换堆132或图2中所示的交换堆290。
SIPO可包含指向其自己私有堆的指针。此外,SIP可包含指向公共交换堆的指针。在至少一个所述实现中,交换堆仅包含指向交换堆本身的指针。每一SIP可保存指向交换堆的多个指针。然而,交换堆中的每一存储器块在系统执行的任何时刻至多为一个SIP所有(即,可访问)。
当执行静态验证时,编程工具160可跟踪交换堆中存储器块的所有权,因为每一块任何时间都至多为一个进程所有。交换堆中的每一块在任何时间可由单个进程访问的事实也提供了有用的互斥保证。
通道
采用IPC体系结构200,通道是由正好两个端点组成的双向消息管道。端点有时被称为通道对等体。通道无损地并按序传递消息。而且,消息通常按发送它们的次序被检索。语义上,每一端点具有接收队列,且在端点上发送使一消息进入对等体上的队列。
通道由通道契约描述。换言之,每一通道的契约指定该通道上的进程间通信约束。例如,契约可指定进程可与哪些其它进程通信以及这样的通信可如何发生。通道的两端一般不是对等的。出于此处的描述性目的,一个端点被称为导入端(Imp),另一端被称为导出端(Exp)。它们分别以类型C.Imp和C.Exp在类型级别上区分,其中C是管控交互的通道契约。
图2比喻地将通道示为电子插头、线和出口。在至少一个所述实现中,通道具有正好且仅两个端点,每一端点为至多一个进程所有。如所述的,通道260链接进程230和OS内核220,并仅具有两个端点262和264。通道270链接进程240和进程250,且仅具有两个端点272和274。通道280是初始将进程250链接到自身但仍仅具有两个端点282和284的新形成的通道。
这些通道由带有正好两个“插头”(表示端点)的“电线”的图形比喻表示。代替导电,这些“线”传导正为每一参与方发送和接收的消息(“双向”),其中“线”被插入。该双向消息传递由通道270旁的有向信封示出。
IPC体系结构200提供了消息传递IPC通信机制。代替使用及时读写某些共享的存储器(如在某些常规方法中),IPC体系结构200将进程间通信限于发送和接收消息。
常规OS消息传递方法是单向机制——通常或者具有一个发送方和多个接收方或者具有多个发送方和一个接收方。与这些常规方法不同,IPC体系结构200的通道是带有正好两个端点和至多两个参与方的双向机制。
这由图2中的通道260和通道270示出。通道260链接进程230和OS内核220,且仅具有这两个端点。通道270链接进程240和进程250,且仅具有这两个端点。
如图2中所示,双向IPC通道中的每个具有正好两个通道端点。每一通道端点一次至多为一个进程所有。例如,一个通道端点为一个进程所有,而另一通道端点为另一进程所有或为操作系统的内核所有。端点可在通道上转移。这样做,这些端点的所有权也转移。
IPC促进器222保证每一消息和每一消息的封装在任何一瞬至多为一个进程所有。这可通过为每一通道采用通道级抽象来完成。而且,在通道的抽象级,消息在任何一瞬至多驻留在一个进程的可访问存储器中。从通信进程的角度,消息中包含或可从消息访问的状态从不共享。在至少一个所述实现中,仅在消息被发送之前,它才可由消息创建方访问。在至少一个所述实现中,仅在消息被接收之后,它才可由消息接收方访问。
所有权
通过在编译时跟踪交换堆中的所有块来保证端点与通道上传输的其它数据的存储器隔离。具体地,静态检查强制对这些资源的访问在拥有资源的程序点进行,且方法不会泄露资源的所有权。所跟踪的资源具有严格的所有权模型。
每一资源在任何时刻至多为一个进程所有。例如,如果在自线程T1到线程T2的消息中发送一端点,则该端点的所有权如下改变:从T1到消息,然后在消息接收时到T2。
在常规方法中,进程制作数据的副本,并传递该数据。因此,该数据现在为多个进程所有。发送数据的进程可仍对其数据副本操作。
采用至少一个所述实现,数据的所有权链接至特定的SIP。数据的所有权与所传递的数据一起传递。从而,进行发送的SIP一旦在它传递数据之后就不能对数据操作,因为它不再具有对数据的访问权,且不能对其制作副本。在此处所述的一个或多个实现中,数据为一个SIP所有,且其所有权在数据一旦通过通道发送之后随数据一起传递。
类似地,通道的每一端点为仅一个SIP所有。端点的所有权随端点的转移而传递给另一SIP。一旦端点被发送,进行发送的SIP就不再具有对它刚发送的通道端点的访问权。
这种(端点和数据的)所有权的转移经由交换堆——诸如图1中所示的交换堆132或图2中所示的交换堆290达成。更具体地,交换堆中的存储器块包含指针(指向主题数据或主题端点的存储器位置)。当在通道上与另一进程交换时,进行发送的进程将指向交换堆中存储器块的指针传递给进行接收的进程。
以此方式,进行发送的进程有效地将主题数据传递给进行接收的进程,但未为自己制作或保留副本。而且,进行发送的进程有效地将主题端点的所有权传递给进行接收的进程,而未保留所有权。所有权转移也可被描述为消息的发送方通过在接收方的端点中由消息交换协议的当前状态确定的位置处存储指向消息的指针来传递所有权。
这些没有数据被复制的交换可被称为“零复制”方法。使用这样的方法,磁盘缓冲器和网络分组可跨多个通道、通过协议堆栈并传输至应用程序进程内,而无需复制发送数据或任何保留发送数据。
通道契约
通道契约由此处所述的实现采用以便于促进进程隔离体系结构。通道契约(以及进程间通信的其它方面)也在“Inter-Process Communications EmployingBi-directional Message Conduits”中描述。
此处是描述通道上的简单交互的示例契约:
contract c1{
in message Request(int x)requi res x>0;
out message Reply(int y);
out message Error();
state Start:Request?
->(Reply !or Error!)
->Start;
}
在此示例中,契约C1声明了三个消息:Request(请求)、Reply(回复)和Error(出错)。每一消息声明指定消息中所包含的自变量的类型。例如,Request和Reply均包含单个整数值,而Error不携带任何值。此外,每一消息可指定进一步限定自变量的Spec#要求子句。
消息也可带有方向标签。从导出方观点编写契约。因此,在此示例中,Request是可由导入方向导出方发送的消息,而Reply和Error是从导出方向导入方发送的。在没有限定词的情况下,消息可在两个方向上行进。
在消息声明之后,契约经由由发送和接收动作驱动的状态机指定可允许的消息交互。所声明的第一状态被视为交互的初始状态。示例契约C1声明被称为Start(开始)的单个状态。在状态名之后,动作Request指示在Start状态中,通道的导出方愿意接收Request消息。在此之后,结构(Reply!or Error!)指定导出方发送(!)Reply或Error消息之一。最后一部分(->Start)指定交互然后继续到Start状态,从而无限循环。
稍微更复杂的示例是网络堆栈契约的一部分:
public contract TcpConnecti onContract{
//请求
in message Connect(uint dstIP,
ushort dstPort);
out message Ready();
//初始状态
state Start:Ready!->ReadyState;
state ReadyState:one{
Connect?->ConnectResult;
BindLocal EndPoint?->BindResult;
Close?->Closed;
}
//绑定至本地端点
state BindResult:one{
OK!->Bound;
InvalidEndPoi nt!->ReadyState;
}
in message Listen();
state Bound:one{
Listen?->ListenResult;
Connect?->ConnectResult;
Close?->Closed;
}
...
契约中的协议指定用于若干目的。它可帮助检测编程错误,或者在运行时或者通过静态分析工具。运行时监控响应于在通道上交换的消息而驱动契约的状态机并注视错误的转移。运行时监控技术独自检测一个程序执行中的错误,但它不能检测诸如诸如非终止的“活性”错误。活性属性是“最终发生了什么好事情”形式的属性,例如“最终程序发送了消息”。静态程序分析可提供进程正确且在所有程序执行中都未被卡住的更强的保证。一般而言,静态分析不限于在一个执行发生时对其监控。例如,它可依赖于检查进程上的指令以便确定进程最终是否会做什么。在逻辑上存在这不会总是起作用的基本结果,但它在众多情况中可良好地起作用。
一个实现使用运行时监控和静态验证的组合。针对通道的契约检查通道上的所有消息,其检测正确性而非活性问题。此处所述的实现具有验证安全性属性的静态检查器。
此外,编译器使用契约来确定通道上可能未完成的消息的最大数目,这允许编译器静态分配通道端点中的缓冲器。静态分配的缓冲器改善通信性能。
端点
通道被表现为表示通道的导入和导出端的一对端点。每一端点具有指定通道遵循哪一契约的类型。端点类型是在每一契约内隐式声明的。契约C1被表示为类,端点类型为该类内的嵌套类型,如下:
·C1.lmp-具有契约C1的通道的导入端点类型。
·C1.Exp-具有契约C1的通道的导出端点类型。
发送/接收方法
每一契约类型包含用于发送和接收契约中所声明的消息的方法。示例提供以下方法:
c1.Imp{
void SendRequest(int x);
void RecvReply(out int y);
void RecvError();
}
c1.Exp{
void RecvRequest(out int x)
void SendReply(int y);
void SendError();
}
发送方法的语义为它们异步发送消息。接收方法阻塞,直到给定消息到达。如果不同的消息首先到达,则发生错误。如果程序通过了契约验证检查,则这样的错误应永远也不会发生。除非接收方确切知道它接下来要求的是哪一消息,否则这些方法不适当。
方法实现
图3示出了用于促进静态可验证SIP的有效进程间通信的方法300和400。这些方法300和400由如图1和2中所述的各种组件中的一个或多个执行。而且,这些方法300和400可用软件、硬件、固件或其组合来执行。
在图3的框302,操作系统(OS)允许在计算机操作系统环境中执行一个或多个软件隔离进程(SIP)。
在框304,OS将特定数据集的所有权与第一SIP相关联。该数据集可以是诸如图1中所示的交换堆132或图2中所示的交换堆290的交换堆中的存储器块。该数据集可以是消息。该数据集可包括数据或指向包含数据的存储器位置的一个或多个指针。而且,该数据集可包括指向通道端点的一个或多个指针。
在框306,OS将特定数据集从第一SIP发送到第二SIP。此处的发送可由向第二SIP提供指向数据集(交换堆中)的指针组成。或者,发送可由向连接至第二SIP的通道的端点编写消息组成。
在框308,OS将特定数据集的所有权从第一SIP转移到第二SIP。当消息在通道上发送时,所有权从进行发送的SIP传递给进行接收的SIP。进行发送的SIP不再保留对该消息的引用。实际上,进行发送的SIP不再具有对所发送消息的访问权。
在发送306和转移308期间,不保留所发送信息的任何副本。实际上,不创建发送信息的任何副本。由于仅传递指向数据集的指针(更精确的,是指向存储数据或指针的存储块的指针),因此不创建和发送任何副本。
该所有权不变性由编程工具和操作系统(诸如编程工具160和OS 100)实施。该所有权不变性用于至少三个目的:第一是防止进程之间的共享。第二是通过消除消息的指针混叠来促进静态程序分析。第三是通过提供可由复制或指针传递来实现的消息传递语义来允许实现的灵活性。
如图4中所示,在402,操作系统允许在计算机操作系统环境中执行一个或多个软件隔离进程(SIP)。
在框404,OS将特定进程间通信通道的特定端点的所有权与第一SIP相关联。该数据集可以是诸如图1中所示的交换堆132或图2中所示的交换堆290的交换堆中的存储器块。该数据集可以是消息。该数据集可包括一个或多个指针。该数据集可包括指向包含一个或多个指针的存储器位置的一个或多个指针。而且,该数据集可包括指向通道端点的一个或多个指针。
在框406,OS将特定进程间通信通道的特定端点从第一SIP发送到第二SIP。此处的发送可由向第二SIP提供指向特定端点(交换堆中)的指针组成。或者,发送可由向连接至第二SIP的通道的端点编写消息组成。
在框408,OS将特定进程间通信通道的特定端点的所有权从第一SIP转移到第二SIP。当端点所有权从进行发送的SIP传递到进行接收的SIP时,进行发送的SIP不再保留对消息的引用。实际上,进行发送的SIP不再具有对所发送数据的访问权。
而且,这种端点所有权的转移在不创建或传递“副本”的情况下进行。由于仅传递指向端点的指针(或指向存储指向端点的指针的存储块的指针),因此不创建和发送任何副本。
验证
编程工具160可验证一个或多个SIP的编程。编程工具160验证所执行的代码是类型安全的,并强制由编译器且在运行时使用强不变性。这样的强不变性包括(作为示例而非限制):
·交换堆中的每一块在任何时刻至多具有一个所有线程(即,进程)。
·交换堆中的块仅可由该块的所有者访问。因此在块释放或所有权转移后没有访问权。
·实施定义和限制进程之间的通信的通道契约(例如在通道上观察到的消息序列对应于通道契约)。
验证的方法实现
图5示出了用于隔离进程的验证的方法500。该方法500由如图1和2中所示的各个组件中的一个或多个执行。而且,该方法500可用软件、硬件、固件或其组合来执行。
在图5的框502,在支持SIP的计算机操作系统环境中编译一个或多个软件隔离进程(SIP)的可执行代码。
在框504,在编译时间期间,编程工具160确认,交换堆中的每一存储器块在任何时刻具有至多一个所有进程。这意味着,在任何一个时刻,仅有一个SIP将拥有任何特定存储器块。
在框506,在编译时间期间,编程工具160确认,交换堆中的每一存储器块仅可由其合法所有者(例如,SIP)访问。
在框508,在编译时间期间,编程工具160确认,遵循通道契约条款。例如,工具确认,观察到控制中所定义的消息的序列。
编程工具160可向用户、程序模块和/或操作系统报告这样的确认的结果。编程工具160可在编译期间执行其验证。此外,它也可在所生成的中间语言代码上验证这些相同的属性。而且,编程工具160可再次验证类型汇编语言的结果形式。
结论
此处所述的技术可用众多方式实现,包括(但不限于)程序模块、通用或专用计算系统、网络服务器和装备、专用电子和硬件、固件,作为一个或多个计算机网络的一部分或其组合。
此处所述的一个或多个实现可经由众多适于使用的公知计算系统、环境和/或配置来实现,包括但不限于:个人计算机(PC)、服务器计算机、手持或膝上型设备、多处理器系统、基于微处理器的系统、可编程消费者电子器件、无限电话和装备、通用和专用设备、专用集成电路(ASIC)、网络PC、薄客户机、厚客户机、机顶盒、小型机、大型机、包括以上系统或设备中任何一个的分布式计算环境等。
尽管用结构特征和/或方法步骤专用的语言描述了一个或多个上述实现,但可以理解,其它实现可无需此处所述的特定的示例性特征或步骤而实现。相反,特定的示例性特征和步骤被公开为一个或多个实现的优选形式。在某些情况中,可略去或简化公知特征以阐明示例性实现的描述。而且,为易于理解起见,某些方法步骤被描绘为分开的步骤;然而,这些分开描绘的步骤不应被解释为在其实现时必然次序相关。