Archive for the ‘continuation’ tag
Xen中的Continuation
我个人理解的计算机科学中的Continuation,即是把一个计算过程具体化(reifier),得到一组可以用来重构这个计算过程的结构。通常情况下,它包含了处理器的栈,还包含了当前的执行点(具体化一点,就是所有寄存器的值),这样处理器就可以在任何时候重构这个计算过程。
一些高级语言,如Python、Ruby、Haskell、LISP等,在VM中对Continuation提供了支持。目前使用的计算机,还是必须手工编写代码才能支持Continuation。
Xen提供了一个hypercall_create_continuation函数,用来resume当前的hypercall。具体做的事情无非就是为客户虚拟机准备好上下文(栈及寄存器),然后重新执行陷入指令。要让虚拟重新执行陷入指令的处理又分为再种情况:假如是PV的虚拟机,把EIP减2,重新执行int 0×82或者syscall指令;假如是HVM,那么不需要对EIP作处理,因为vmcall产生的是fault,指令会重新自动执行。
Xen中的Continuation仅仅用于重新执行hypercall,对栈和寄存器的操作比较少,速度是有保证的。
那么,Xen在什么时候需要创建Continuation呢?常见的代码形式是:
if ( hypercall_preempt_check() )
hypercall_create_continuation(...)
hypercall_preempt_check又是干什么的呢?假如当前物理CPU有等待处理的softirq,或者PV中的VCPU中有可投递的upcall(pending且!masked),那么它的返回值就为真。(HVM这里先不讨论)
即是说,Xen在执行某些Hypercall的时候,有可能处于一种不能抢占CPU的状态,所以必须让客户虚拟机重新再执行一次Hypercall。
受影响的Hypercall有:
__HYPERVISOR_hvm_op
__HYPERVISOR_mmuext_op
__HYPERVISOR_mmu_update
__HYPERVISOR_domctl
__HYPERVISOR_set_trap_table
__HYPERVISOR_memory_op
__HYPERVISOR_multicall
__HYPERVISOR_console_io
本人目前的看法是,这些Hypercall在有upcall或者softirq处于pending的状态时候执行的话,都会有影响虚拟机状态一致性的可能。以console io为例,虚拟机和consoled之间的事件通知,就是用的event channel机制。处于pending状态的event很可能就是IO通信产生的。假如虚拟机在调用__HYPERVISOR_console_io之前没有先把所有的event都处理完,那么就会造成数据的丢失。
但是其他的Hypercall为什么不会有这样的问题呢?那自然是因为其他的Hypercall在执行的时候可以保证当时所处的状态是“干净”的。
草草看了一下代码,写下了上面的文字。水平所限,错误在所难免,欢迎指正。
Elisp不支持闭包,白忙了
今天下午研究了一下Continuation,在Wikipedia上看到了Continuation Passing Style的相关介绍,带有例程(不过是用Scheme写的)。既然自己在用Emacs,那么试试把例子都用Elisp实现一下吧。
其中有一个函数,用来制作支持CPS的函数,原型是这样的:
(define (cps-prim f)
(lambda args
(let ((r (reverse args)))
((car r) (apply f
(reverse (cdr r)))))))
这样用,比如说要制作一个支持CPS的减法运算:
(define cps- (cps-prim -))
假如不使用cps-prim,那么每个函数都要这样写:
(define cps- (a b k) (k (- a b)))
很显然,使用cps-prim更加方便点。于是我打算用Elisp也做一个同样的函数,谁让我这么懒呢。
Elisp比较乱,所以写了挺久的,但是总算是写出来了:
(defun cps-prim (f)
#'(lambda (args)
(let ((r (reverse args)))
(funcall (car r) (apply f
(reverse (cdr r)))))))
(fset 'cps- (cps-prim '-))
但是使用cps-的时候,会提示f无值。好吧,查一个info,心彻底凉了。11.9.2中明确写到,Elisp是不支持闭包的,所以f在cps-中是unbound的。想偷懒偷不成咯。
再进一步想想,Elisp不支持闭包,是否就不支持高阶函数呢?个人程序设计语言方面没什么了解,只能google了。显然我不是第一个想到这个问题的,还真是发现了一些有趣的东西。
http://lambda-the-ultimate.org/node/1936
有人说:
Closure = Function x Environment
不得不说,这个等式,比一个冗长的定义更清楚。