88 lines
2.7 KiB
Plaintext
88 lines
2.7 KiB
Plaintext
|
Date: Fri, 25 Jun 93 13:31:50 -0400
|
||
|
From: Jonathan Rees <jar@martigny.ai.mit.edu>
|
||
|
To: sheldon@lcs.mit.edu
|
||
|
Cc: jar@martigny.ai.mit.edu
|
||
|
Subject: call-back
|
||
|
Message-Id: <9306251331.aa11673@mintaka.lcs.mit.edu>
|
||
|
|
||
|
|
||
|
Hmm... I think the convention is:
|
||
|
|
||
|
1. Scheme calls C (e.g. the rpc server) as usual using EXTERNAL-CALL.
|
||
|
2. C calls the VM's entry point restart(value).
|
||
|
3. That causes the original Scheme code to think that your C function
|
||
|
has returned value, when in fact it hasn't.
|
||
|
4. If Scheme later executes a VM-RETURN instruction, then
|
||
|
the C call to restart() will return with the specified value.
|
||
|
|
||
|
So you need to write some Scheme code that looks vaguely like this:
|
||
|
|
||
|
(let ((communication-block (make-vector 100)))
|
||
|
(let loop ((status (external-call rpc-server communication-block)))
|
||
|
(if status ;Boolean
|
||
|
(begin (store-somewhere-in-communication-block!
|
||
|
(apply (choose-a-procedure ...)
|
||
|
(extract-some-arguments ...)))
|
||
|
;; communication-block might be moved by GC; give new
|
||
|
;; address back to C
|
||
|
(loop (vm-return 0 communication-block))))))
|
||
|
|
||
|
The procedure, number of arguments, and the arguments themselves must
|
||
|
be encoded in the argument block somehow. You must not put Scheme
|
||
|
values (including the argument block) in C variables that are live
|
||
|
across calls to the VM. Therefore the procedures have to numbered
|
||
|
(stored in a vector, say) or something.
|
||
|
|
||
|
Apparently the first argument to VM-RETURN is ignored.
|
||
|
|
||
|
(define-primitive op/vm-return (fixnum-> any->) ;from vm/prim.scm
|
||
|
(lambda (key value)
|
||
|
(set! *val* value)
|
||
|
;; TTreturn_value = 0;
|
||
|
;; return(0L);}
|
||
|
return-option/exit)) ; the VM returns this value
|
||
|
|
||
|
The relevant code from scheme48vm.c (actually, the source from
|
||
|
vm/resume.scm):
|
||
|
|
||
|
long restart(long value)
|
||
|
{
|
||
|
(set! *val* value)
|
||
|
(let loop ()
|
||
|
(let ((option (interpret)))
|
||
|
;; option_880X = TTrun_machine((long)Tinterpret);
|
||
|
(cond ((= option return-option/exit)
|
||
|
*val*)
|
||
|
((= option return-option/external-call)
|
||
|
(set! *val* (call-external-value ; type inference hack
|
||
|
(fetch (address-after-header
|
||
|
(external-value *val*)))
|
||
|
*nargs*
|
||
|
(pointer-to-top-of-stack)))
|
||
|
(stack-add (- 0 (+ *nargs* 1))) ; remove proc and args
|
||
|
(loop))
|
||
|
(else
|
||
|
(error "unkown VM return option" option)
|
||
|
-1))))
|
||
|
}
|
||
|
|
||
|
|
||
|
The relevant code from unix.c:
|
||
|
|
||
|
call_external_value( long proc, long nargs, long *args )
|
||
|
{
|
||
|
return ((long(*)())proc)(nargs, args);
|
||
|
}
|
||
|
|
||
|
/* Driver loop for tail-recursive calls */
|
||
|
|
||
|
long TTreturn_value;
|
||
|
|
||
|
long TTrun_machine(proc)
|
||
|
long (*proc) (void);
|
||
|
{
|
||
|
while (proc != 0)
|
||
|
proc = (long (*) (void)) (*proc)();
|
||
|
return TTreturn_value;
|
||
|
}
|