[movitz-cvs] CVS update: movitz/losp/ll-testing.lisp

Frode Vatvedt Fjeld ffjeld at common-lisp.net
Tue Apr 26 22:23:17 UTC 2005


Update of /project/movitz/cvsroot/movitz/losp
In directory common-lisp.net:/tmp/cvs-serv29766

Modified Files:
	ll-testing.lisp 
Log Message:
Threads have landed!

Date: Wed Apr 27 00:23:14 2005
Author: ffjeld

Index: movitz/losp/ll-testing.lisp
diff -u movitz/losp/ll-testing.lisp:1.3 movitz/losp/ll-testing.lisp:1.4
--- movitz/losp/ll-testing.lisp:1.3	Mon Apr 18 09:08:58 2005
+++ movitz/losp/ll-testing.lisp	Wed Apr 27 00:23:14 2005
@@ -10,7 +10,7 @@
 ;;;; Author:        Frode Vatvedt Fjeld <frodef at acm.org>
 ;;;; Created at:    Thu Apr 14 08:18:43 2005
 ;;;;                
-;;;; $Id: ll-testing.lisp,v 1.3 2005/04/18 07:08:58 ffjeld Exp $
+;;;; $Id: ll-testing.lisp,v 1.4 2005/04/26 22:23:14 ffjeld Exp $
 ;;;;                
 ;;;;------------------------------------------------------------------
 
@@ -43,9 +43,7 @@
     (check-type entries (integer 0 *))
     (let ((limit (1- (* 8 entries)))
 	  (base (+ 2 (+ (object-location table)
-			(memref nil (movitz-type-slot-offset 'movitz-run-time-context
-							     'physical-address-offset)
-				:type :lisp)))))
+			(location-physical-offset)))))
       (%lgdt base limit)
       (values table limit))))
 
@@ -54,8 +52,224 @@
   (loop for i from start below end
       do (format t "~&~2D: base: #x~8,'0X, limit: #x~5,'0X, type-s-dpl-p: ~8,'0b, avl-x-db-g: ~4,'0b~%"
 		 i
-		 (segment-descriptor-base table i)
+		 (* 4 (segment-descriptor-base-location table i))
 		 (segment-descriptor-limit table i)
 		 (segment-descriptor-type-s-dpl-p table i)
 		 (segment-descriptor-avl-x-db-g table i)))
-  (values))
\ No newline at end of file
+  (values))
+
+
+
+(defmacro control-stack-esp (stack)
+  `(stack-frame-ref ,stack 0 1))
+
+(defmacro control-stack-ebp (stack)
+  `(stack-frame-ref ,stack 0 0))
+
+(defun control-stack-init (&optional (stack (make-array 254 :element-type '(unsigned-byte 32))))
+  (let ((i (length stack)))
+    (setf (control-stack-esp stack) i
+	  (control-stack-ebp stack) 0)
+    stack))
+
+(defun control-stack-push (value stack &optional (type :lisp))
+  (let ((i (decf (control-stack-esp stack))))
+    (assert (< 1 i (length stack)))
+    (setf (stack-frame-ref stack i 0 type) value)))
+
+(defun control-stack-enter-frame (stack &optional function)
+  (control-stack-push (control-stack-ebp stack) stack)
+  (setf (control-stack-ebp stack) (control-stack-esp stack))
+  (when function
+    (check-type function function)
+    (control-stack-push function stack))
+  stack)
+
+(defun stack-stopper (&rest args)
+  (declare (ignore args))
+  (declare (without-function-prelude))
+  (error "Stack stop.")
+  (format *terminal-io* "~&Stack-stopper halt.")
+  (loop (halt-cpu)))
+
+(defun control-stack-fixate (stack)
+  (let ((stack-base (+ 2 (object-location stack))))
+    (do ((frame (control-stack-ebp stack)))
+	((zerop (stack-frame-uplink stack frame)))
+      (assert (typep (stack-frame-funobj stack frame) 'function))
+      (let ((previous-frame frame))
+	(setf frame (stack-frame-uplink stack frame))
+	(incf (stack-frame-ref stack previous-frame 0)
+	      stack-base)))
+    (values (+ (control-stack-ebp stack) stack-base)
+	    (+ (control-stack-esp stack) stack-base))))	       
+
+(defun make-thread (segment-descriptor-table)
+  (let* ((fs-index 8)
+	 (thread (muerte::clone-run-time-context :name 'subthread)))
+    (setf (segment-descriptor segment-descriptor-table fs-index)
+      (segment-descriptor segment-descriptor-table (truncate (segment-register :fs) 8)))
+    (warn "Thread ~S FS base: ~S"
+	  thread
+	  (setf (segment-descriptor-base-location segment-descriptor-table fs-index)
+	    (+ (object-location thread)
+	       (muerte::location-physical-offset))))
+    (values thread (* 8 fs-index))))
+
+
+(defun control-stack-bootstrap (stack function &rest args)
+  (declare (dynamic-extent args))
+  (check-type function function)
+  (control-stack-init stack)
+  (control-stack-push 0 stack)
+  (control-stack-enter-frame stack #'stack-stopper)
+  (let ((stack-top (+ (object-location stack) 2 (length stack)))
+	(stack-bottom (+ (object-location stack) 2)))
+    (dolist (arg (cddr args))
+      (control-stack-push arg stack))
+    (control-stack-push (+ 2 1 (object-location (funobj-code-vector #'stack-stopper)))
+			stack)		; XXX The extra word skips the frame-setup.
+    (multiple-value-bind (ebp esp)
+	(control-stack-fixate stack)
+      (stack-yield stack esp ebp
+		   :eax (car args)
+		   :ebx (cadr args)
+		   :ecx (length args)
+		   :esi function)))
+  stack)
+
+(defun test-tt ()
+  (multiple-value-bind (thread stack)
+      (muerte.init::threading)
+    (control-stack-bootstrap stack #'format t "Hello world!")))
+
+(defun test-tr (function &rest args)
+  (declare (dynamic-extent args))
+  (assert (= 2 (length args)))
+  (multiple-value-bind (thread fs)
+      (make-thread muerte.init::*segment-descriptor-table*)
+    (let ((cushion nil)
+	  (stack (control-stack-init-for-yield (make-array 4094 :element-type '(unsigned-byte 32))
+					       function args)))
+      (multiple-value-bind (ebp esp)
+	  (control-stack-fixate stack)
+	(setf (control-stack-ebp stack) ebp
+	      (control-stack-esp stack) esp))
+      (setf (%run-time-context-slot 'dynamic-env thread) 0
+	    (%run-time-context-slot 'stack-vector thread) stack
+	    (%run-time-context-slot 'stack-top thread) (+ 2 (object-location stack)
+							  (length stack))
+	    (%run-time-context-slot 'stack-bottom thread) (+ (object-location stack) 2
+							     (or cushion
+								 (if (>= (length stack) 200)
+								     100
+								   0))))
+      (values thread fs stack))))
+
+(defun stack-bootstrapper (&rest args)
+  (declare (ignore args))
+  (with-inline-assembly (:returns :nothing) (:break))
+  (let ((frame (current-stack-frame)))
+    (assert (eql 0 (stack-frame-uplink nil frame)))
+    (let ((function (stack-frame-ref nil frame 1))
+	  (numargs (stack-frame-ref nil frame 2)))
+      (warn "[~S] bootstrapping function ~S with ~D args." frame function numargs)
+      (check-type function function)
+      (check-type numargs (integer 0 #xffff))
+      (with-inline-assembly (:returns :multiple-values)
+	(:load-lexical (:lexical-binding function) :esi)
+	(:movl (:ebp #x0c) :eax)
+	(:movl (:ebp #x10) :ebx)
+	(:call (:esi (:offset movitz-funobj code-vector%2op))))))
+  (error "Stack bootstrapper stop.")
+  (format *terminal-io* "~&stack-bootstrapper halt.")
+  (loop (halt-cpu)))
+
+(defun control-stack-init-for-yield (stack function args)
+  (check-type function function)
+  (control-stack-init stack)
+  (control-stack-push (second args) stack)
+  (control-stack-push (first args) stack)
+  (control-stack-push (length args) stack)
+  (control-stack-push function stack)
+  (control-stack-enter-frame stack #'stack-bootstrapper)
+  ;; Now pretend stack-bootstrapper called yield. First, the return address
+  (control-stack-push (+ 2 2 (object-location (funobj-code-vector #'stack-bootstrapper)))
+		      stack)		; XXX The extra 2 words skip the frame-setup,
+					; XXX which happens to be 8 bytes..
+  (control-stack-enter-frame stack #'yield)
+  (control-stack-push 0 stack)		; XXX shouldn't need this?
+  stack)
+  
+
+(defun yield (target-rtc fs)
+  (assert (not (eq target-rtc (current-run-time-context))))
+  (let ((my-stack (%run-time-context-slot 'stack-vector))
+	(target-stack (%run-time-context-slot 'stack-vector target-rtc)))
+    (assert (not (eq my-stack target-stack)))
+    (let ((esp (control-stack-esp target-stack))
+	  (ebp (control-stack-ebp target-stack)))
+      (assert (location-in-object-p target-stack esp))
+      (assert (location-in-object-p target-stack ebp))
+      (assert (eq (memref ebp -4) (asm-register :esi)) ()
+	"Cannot yield to a non-yield frame.")
+      ;; Push eflags for later..
+      (setf (memref (decf esp) 0) (eflags))
+      ;; Enable someone to yield back here..
+      (setf (control-stack-ebp my-stack) (asm-register :ebp)
+	    (control-stack-esp my-stack) (asm-register :esp))
+      (with-inline-assembly (:returns :nothing)
+	(:cli)
+	(:load-lexical (:lexical-binding fs) :untagged-fixnum-ecx)
+	(:movw :cx :fs)
+	(:load-lexical (:lexical-binding ebp) :eax)
+	(:load-lexical (:lexical-binding esp) :ebx)
+	(:movl :eax :ebp)
+	(:movl :ebx :esp)
+	(:popfl)))))
+
+(defun stack-yield (stack esp ebp &key eax ebx ecx edx esi eflags (dynamic-env 0) cushion)
+  "Activate stack for the current run-time-context, and load the indicated CPU state.
+EIP is loaded from ESI's code-vector."
+  (assert (not (eq stack (%run-time-context-slot 'stack-vector))))
+  (assert (location-in-object-p stack esp))
+  (assert (location-in-object-p stack ebp))
+  (assert (or (= 0 dynamic-env) (location-in-object-p stack dynamic-env)))
+  (let ((stack-top (+ (object-location stack) 2 (length stack)))
+	(stack-bottom (+ (object-location stack) 2
+			 (or cushion
+			     (if (>= (length stack) 200)
+				 100
+			       0)))))
+    (with-inline-assembly (:returns :non-local-exit)
+      (:clc)
+      (:pushfl)
+      (:popl :ebx)
+      (:compile-form (:result-mode :eax) eflags)
+      (:cmpl :edi :eax)
+      (:je 'no-eflags-provided)
+      (:movl :eax :ebx)
+     no-eflags-provided
+      (:locally (:movl :ebx (:edi (:edi-offset raw-scratch0)))) ; Keep eflags in raw-scratch0
+      (:cli)				; Disable interrupts for a little while
+      (:compile-form (:result-mode :eax) stack)
+      (:locally (:movl :eax (:edi (:edi-offset stack-vector))))
+      (:compile-form (:result-mode :eax) dynamic-env)
+      (:locally (:movl :eax (:edi (:edi-offset dynamic-env))))
+      (:compile-two-forms (:eax :ebx) stack-top stack-bottom)
+      (:locally (:movl :eax (:edi (:edi-offset stack-top))))
+      (:locally (:movl :ebx (:edi (:edi-offset stack-bottom))))
+
+      (:compile-two-forms (:eax :ebx) esp ebp)
+      (:locally (:movl :eax (:edi (:edi-offset scratch1))))
+      (:locally (:movl :ebx (:edi (:edi-offset scratch2))))
+
+      (:compile-form (:result-mode :untagged-fixnum-ecx) ecx)
+      (:compile-two-forms (:eax :ebx) eax ebx)
+      (:compile-two-forms (:edx :esi) edx esi)
+      (:locally (:movl (:edi (:edi-offset scratch1)) :esp))
+      (:locally (:movl (:edi (:edi-offset scratch2)) :ebp))
+      (:locally (:pushl (:edi (:edi-offset raw-scratch0)))) ; reset eflags
+      (:popfl)
+      (:jmp (:esi (:offset movitz-funobj code-vector))))))
+




More information about the Movitz-cvs mailing list