2020-10-26 21:08:24 -04:00
|
|
|
;;-*-Lisp-*-
|
2020-09-04 14:44:23 -04:00
|
|
|
(in-package goal)
|
|
|
|
|
|
|
|
;; name: gstate.gc
|
|
|
|
;; name in dgo: gstate
|
|
|
|
;; dgos: KERNEL
|
2021-02-16 20:37:48 -05:00
|
|
|
|
|
|
|
#|
|
|
|
|
Summary of state system:
|
|
|
|
|
|
|
|
A process can be put into a state, using enter-state, or the go macro.
|
|
|
|
This will set up the process to run the appropriate handler functions defined by the state.
|
|
|
|
The state handlers are:
|
|
|
|
- enter : gets run before trans on the first time the state is used. Can be #f. Must return.
|
|
|
|
- trans : gets run before code each time the code is run. Can be #f. Must return.
|
|
|
|
- code : main thread. Can suspend. If it returns, the process dies
|
|
|
|
- exit : gets run when leaving a state. must return.
|
|
|
|
- event : not sure of the details here yet.
|
|
|
|
|
2021-03-23 15:56:23 -04:00
|
|
|
You can use "go" to change the state of a process. This causes the process main thread execution to be abandoned.
|
2021-02-16 20:37:48 -05:00
|
|
|
If the main thread has exits/protects on the stack frame, they will be run first to clean up.
|
|
|
|
|
|
|
|
There are several ways to "go"
|
|
|
|
- go during init: when a process is being initialized with run-function-in-process, you can "go".
|
2021-03-23 15:56:23 -04:00
|
|
|
this causes the run-function-in-process to return immediately, and the next time the process is dispatched
|
2021-02-16 20:37:48 -05:00
|
|
|
it will go into the other state. This will automatically set the process to waiting-to-run,
|
|
|
|
and shrink the process heap, if appropriate
|
|
|
|
|
|
|
|
- go from outside the process. You can temporarily set pp to another process, and have that
|
2021-06-04 13:22:50 -04:00
|
|
|
process go to another state. The actual go will occur the next time the process is scheduled.
|
2021-03-23 15:56:23 -04:00
|
|
|
Use the go-process macro to do this.
|
2021-02-16 20:37:48 -05:00
|
|
|
|
|
|
|
- go from a non-main thread in the right process. You can do a go from a temporary thread, like trans or post.
|
|
|
|
If you do it from post, the go returns. If you do it from any other thread, the temporary thread
|
|
|
|
is immediately abandonded. Like the previous two, it will defer the actual go until the next time the
|
|
|
|
process runs.
|
|
|
|
|
|
|
|
- go from the main thread of the main process. This causes the (-> pp state) to change, the stack frames
|
|
|
|
to be cleaned up, and the old state's exit to be called. It will reset the stack, then run the code.
|
2021-03-23 15:56:23 -04:00
|
|
|
Unlike the others, this means you "go" immediately.
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-08-17 20:54:03 -04:00
|
|
|
The compiler has two special hooks related to states: go-hook and define-state-hook.
|
|
|
|
These take care of doing a go and a state definition and properly checking types.
|
|
|
|
|
|
|
|
The define-state-hook takes a state object and handlers and defines a global symbol
|
|
|
|
with the appropriate state type.
|
|
|
|
|
|
|
|
The go-hook calls enter state and sets (-> proc next-state) for the given process.
|
|
|
|
It type checks the arguments for the entry function.
|
2021-02-16 20:37:48 -05:00
|
|
|
|
|
|
|
|#
|
|
|
|
|
|
|
|
;; cause the current process to change state
|
|
|
|
(defmacro go (next-state &rest args)
|
|
|
|
`(with-pp
|
2021-08-17 20:54:03 -04:00
|
|
|
(go-hook pp ,next-state ,@args)
|
2021-02-16 20:37:48 -05:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2021-08-17 20:54:03 -04:00
|
|
|
(defmacro go-virtual (state-name &key (proc self) &rest args)
|
|
|
|
"Change the current process to the virtual state of the given process."
|
|
|
|
`(go (method-of-object ,proc ,state-name) ,@args)
|
|
|
|
)
|
|
|
|
|
2021-02-16 20:37:48 -05:00
|
|
|
;; cause the given process to change state.
|
2021-08-17 20:54:03 -04:00
|
|
|
(defmacro go-process (proc next-state &rest args)
|
2021-02-16 20:37:48 -05:00
|
|
|
`(with-pp
|
|
|
|
(protect (pp)
|
|
|
|
(set! pp ,proc)
|
2021-08-17 20:54:03 -04:00
|
|
|
(go-hook pp ,next-state ,@args)
|
2021-02-16 20:37:48 -05:00
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
;; run the given function in a process right now.
|
|
|
|
;; will return to here when:
|
|
|
|
;; - you return
|
|
|
|
;; - you deactivate
|
|
|
|
;; - you go
|
|
|
|
;; - you throw to 'initialize
|
|
|
|
(defmacro run-now-in-process (proc func &rest args)
|
|
|
|
`((the (function _varargs_ object) run-function-in-process)
|
|
|
|
,proc ,func ,@args
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
;; sets the main thread of the given process to run the given thing.
|
|
|
|
;; this resets the main thread stack back to the top
|
|
|
|
(defmacro run-next-time-in-process (proc func &rest args)
|
|
|
|
`((the (function _varargs_ object) set-to-run)
|
|
|
|
(-> ,proc main-thread) ,func ,@args
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2022-04-19 18:17:27 -04:00
|
|
|
(defmacro process-new-function (proc-type func &key (from *default-dead-pool*) &key (to *default-pool*) &key (name #f) &key (stack-size #x4000) &key (stack *kernel-dram-stack*) &rest args)
|
2021-08-15 23:04:04 -04:00
|
|
|
"Start a new process that runs a function on its main thread.
|
2021-08-16 02:44:05 -04:00
|
|
|
Returns a pointer to the new process (or #f? on error)."
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-08-15 22:50:36 -04:00
|
|
|
(with-gensyms (new-proc)
|
2021-09-06 20:35:03 -04:00
|
|
|
`(let ((,new-proc (the-as ,proc-type (get-process ,from ,proc-type ,stack-size))))
|
2021-08-15 22:50:36 -04:00
|
|
|
(when ,new-proc
|
2021-09-06 20:35:03 -04:00
|
|
|
((method-of-type ,proc-type activate) ,new-proc ,to ,(if name name `(quote ,proc-type)) ,stack)
|
2021-08-15 23:04:04 -04:00
|
|
|
(run-next-time-in-process ,new-proc ,func ,@args)
|
2021-09-06 20:35:03 -04:00
|
|
|
(the (pointer ,proc-type) (-> ,new-proc ppointer))
|
2021-08-15 23:04:04 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2022-04-19 18:17:27 -04:00
|
|
|
(defmacro process-new (proc-type init &key (from *default-dead-pool*) &key (to *default-pool*) &key (name #f) &key (stack-size #x4000) &key (stack *kernel-dram-stack*) &rest args)
|
2021-08-15 23:04:04 -04:00
|
|
|
"Start a new process and run an init function on it.
|
|
|
|
Returns a pointer to the new process, or #f (or is it 0?) if something goes wrong."
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-08-15 23:04:04 -04:00
|
|
|
(with-gensyms (new-proc)
|
2021-09-06 20:35:03 -04:00
|
|
|
`(let ((,new-proc (the-as ,proc-type (get-process ,from ,proc-type ,stack-size))))
|
2021-08-15 23:04:04 -04:00
|
|
|
(when ,new-proc
|
2021-09-06 20:35:03 -04:00
|
|
|
((method-of-type ,proc-type activate) ,new-proc ,to ,(if name name `(quote ,proc-type)) ,stack)
|
2022-04-19 18:17:27 -04:00
|
|
|
(run-now-in-process ,new-proc ,init ,@args)
|
2021-09-06 20:35:03 -04:00
|
|
|
(the (pointer ,proc-type) (-> ,new-proc ppointer))
|
2021-08-15 22:50:36 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2021-02-16 20:37:48 -05:00
|
|
|
;; display a listing of active processes.
|
|
|
|
(defmacro ps (&key (detail #f))
|
|
|
|
`(inspect-process-tree *active-pool* 0 0 ,detail)
|
|
|
|
)
|
|
|
|
|
2021-07-25 00:23:30 -04:00
|
|
|
;; use a compile-time list to keep track of the type of an anonymous behavior.
|
|
|
|
(seval (define *defstate-type-stack* '()))
|
|
|
|
(desfun def-state-check-behavior (beh-form beh-type)
|
|
|
|
"check if code block is an anonymous behavior. needed for anonymous behaviors on defstate."
|
2021-02-16 20:37:48 -05:00
|
|
|
|
2021-07-25 00:23:30 -04:00
|
|
|
(when (and (pair? beh-form) (eq? (first beh-form) 'behavior))
|
|
|
|
(push! *defstate-type-stack* beh-type)
|
|
|
|
)
|
|
|
|
)
|
2021-09-06 20:35:03 -04:00
|
|
|
(defmacro clear-def-state-stack ()
|
|
|
|
(set! *defstate-type-stack* '())
|
|
|
|
`(none)
|
|
|
|
)
|
2021-11-23 18:25:57 -05:00
|
|
|
;; *no-state* is just used for the compiler to know whether a handler was actually set or not
|
2021-07-25 00:23:30 -04:00
|
|
|
(defmacro defstate (state-name parents
|
2021-08-17 20:54:03 -04:00
|
|
|
&key (virtual #f)
|
2021-11-23 18:25:57 -05:00
|
|
|
&key (event *no-state*)
|
|
|
|
&key (enter *no-state*)
|
|
|
|
&key (trans *no-state*)
|
|
|
|
&key (exit *no-state*)
|
|
|
|
&key (code *no-state*)
|
|
|
|
&key (post *no-state*)
|
2021-08-17 20:54:03 -04:00
|
|
|
)
|
2021-07-25 00:23:30 -04:00
|
|
|
"Define a new state!"
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-07-25 00:23:30 -04:00
|
|
|
(with-gensyms (new-state)
|
|
|
|
(let ((defstate-type (first parents)))
|
|
|
|
(when (not (null? *defstate-type-stack*))
|
2021-09-06 20:35:03 -04:00
|
|
|
(fmt #t "*defstate-type-stack* leaked! An error probably happened in a previous defstate. stack is: {}"
|
|
|
|
*defstate-type-stack*)
|
2021-08-17 20:54:03 -04:00
|
|
|
)
|
2021-07-25 00:23:30 -04:00
|
|
|
(set! *defstate-type-stack* '())
|
2021-09-06 20:35:03 -04:00
|
|
|
;; check for default handlers
|
|
|
|
(let ((default-handlers (assoc defstate-type *default-state-handlers*)))
|
|
|
|
(when (not (null? default-handlers))
|
2021-12-04 15:34:03 -05:00
|
|
|
;;(fmt #t "found default-handlers for {}: {}\n" defstate-type default-handlers)
|
|
|
|
;; event
|
2022-01-27 19:33:34 -05:00
|
|
|
(set! default-handlers (cadr default-handlers))
|
2021-12-04 15:34:03 -05:00
|
|
|
(when (and (eq? event '*no-state*) (car default-handlers))
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! event (car default-handlers)))
|
2021-12-04 15:34:03 -05:00
|
|
|
;; enter
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! default-handlers (cdr default-handlers))
|
2021-12-04 15:34:03 -05:00
|
|
|
(when (and (eq? enter '*no-state*) (car default-handlers))
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! enter (car default-handlers)))
|
2021-12-04 15:34:03 -05:00
|
|
|
;; trans
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! default-handlers (cdr default-handlers))
|
2021-12-04 15:34:03 -05:00
|
|
|
(when (and (eq? trans '*no-state*) (car default-handlers))
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! trans (car default-handlers)))
|
2021-12-04 15:34:03 -05:00
|
|
|
;; exit
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! default-handlers (cdr default-handlers))
|
2021-12-04 15:34:03 -05:00
|
|
|
(when (and (eq? exit '*no-state*) (car default-handlers))
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! exit (car default-handlers)))
|
2021-12-04 15:34:03 -05:00
|
|
|
;; code
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! default-handlers (cdr default-handlers))
|
2021-12-04 15:34:03 -05:00
|
|
|
(when (and (eq? code '*no-state*) (car default-handlers))
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! code (car default-handlers)))
|
2021-12-04 15:34:03 -05:00
|
|
|
;; post
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! default-handlers (cdr default-handlers))
|
2021-12-04 15:34:03 -05:00
|
|
|
(when (and (eq? post '*no-state*) (car default-handlers))
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! post (car default-handlers)))
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-09-06 20:35:03 -04:00
|
|
|
(set! default-handlers (cdr default-handlers))
|
|
|
|
)
|
|
|
|
)
|
2021-07-25 00:23:30 -04:00
|
|
|
(def-state-check-behavior event defstate-type)
|
|
|
|
(def-state-check-behavior enter defstate-type)
|
|
|
|
(def-state-check-behavior trans defstate-type)
|
|
|
|
(def-state-check-behavior exit defstate-type)
|
|
|
|
(def-state-check-behavior code defstate-type)
|
|
|
|
(def-state-check-behavior post defstate-type)
|
|
|
|
`(let ((,new-state (new 'static 'state
|
2021-08-17 20:54:03 -04:00
|
|
|
:name (quote ,state-name)
|
|
|
|
:next #f
|
|
|
|
:exit #f
|
|
|
|
:code #f
|
|
|
|
:trans #f
|
|
|
|
:post #f
|
|
|
|
:enter #f
|
|
|
|
:event #f
|
|
|
|
)
|
|
|
|
))
|
|
|
|
;; the compiler will set the fields of the given state and define the symbol.
|
|
|
|
;; This way it can check the individual function types, make sure they make sense, and create
|
|
|
|
;; a state with the appropriate type.
|
|
|
|
,(if virtual
|
2022-01-31 20:44:54 -05:00
|
|
|
`(define-virtual-state-hook ,state-name ,defstate-type ,new-state ,(eq? virtual 'override) :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
2021-08-17 20:54:03 -04:00
|
|
|
`(define-state-hook ,state-name ,defstate-type ,new-state :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
|
|
|
)
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-08-17 20:54:03 -04:00
|
|
|
)
|
2021-02-16 20:37:48 -05:00
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2021-07-25 00:23:30 -04:00
|
|
|
|
|
|
|
(defmacro behavior (bindings &rest body)
|
|
|
|
"Define an anonymous behavior for a process state. This may only be used inside a defstate!"
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-07-25 00:23:30 -04:00
|
|
|
(let ((behavior-type (first *defstate-type-stack*)))
|
2021-08-17 20:54:03 -04:00
|
|
|
(pop! *defstate-type-stack*)
|
|
|
|
`(lambda :behavior ,behavior-type ,bindings ,@body)
|
|
|
|
)
|
2021-07-25 00:23:30 -04:00
|
|
|
)
|
2021-02-16 20:37:48 -05:00
|
|
|
|
2021-09-06 20:35:03 -04:00
|
|
|
;; set the default handler functions for a process's state handlers
|
|
|
|
(seval (define *default-state-handlers* '()))
|
|
|
|
(defmacro defstatehandler (proc
|
|
|
|
&key (event #f)
|
|
|
|
&key (enter #f)
|
|
|
|
&key (trans #f)
|
|
|
|
&key (exit #f)
|
|
|
|
&key (code #f)
|
|
|
|
&key (post #f))
|
2022-01-27 19:33:34 -05:00
|
|
|
(let ((old (assoc proc *default-state-handlers*))
|
|
|
|
(new (list proc (list event enter trans exit code post))))
|
|
|
|
(if (null? old)
|
|
|
|
(append!! *default-state-handlers* new) ;; add new set of default handlers
|
|
|
|
(dolist (hnd *default-state-handlers*) ;; replace old handlers with new ones
|
|
|
|
(when (eq? (car hnd) old)
|
|
|
|
(set-car! hnd new)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2021-09-06 20:35:03 -04:00
|
|
|
)
|
|
|
|
`(none)
|
|
|
|
)
|
|
|
|
|
2021-02-16 20:37:48 -05:00
|
|
|
(defmethod new state
|
|
|
|
((allocation symbol)
|
|
|
|
(type-to-make type)
|
2021-11-15 19:05:28 -05:00
|
|
|
(name symbol)
|
2021-02-16 20:37:48 -05:00
|
|
|
(code function)
|
2021-08-17 20:54:03 -04:00
|
|
|
(trans (function none))
|
|
|
|
(enter function)
|
|
|
|
(exit (function none))
|
2021-07-23 18:30:49 -04:00
|
|
|
(event (function process int symbol event-message-block object)))
|
2021-02-16 20:37:48 -05:00
|
|
|
"Allocate a new state. It seems like this isn't really used much and most states are
|
|
|
|
statically allocated and as a result don't have the constructor called."
|
|
|
|
(let ((obj (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
|
|
|
|
(set! (-> obj name) name)
|
2021-07-23 18:30:49 -04:00
|
|
|
(set! (-> obj next) #f)
|
2021-02-16 20:37:48 -05:00
|
|
|
(set! (-> obj exit) exit)
|
|
|
|
(set! (-> obj code) code)
|
|
|
|
(set! (-> obj trans) trans)
|
2021-07-23 18:30:49 -04:00
|
|
|
(set! (-> obj post) #f)
|
2021-02-16 20:37:48 -05:00
|
|
|
(set! (-> obj enter) enter)
|
|
|
|
(set! (-> obj event) event)
|
|
|
|
obj
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
(defun inherit-state ((child state) (parent state))
|
|
|
|
"Copy handler functions from parent to child"
|
2021-08-17 20:54:03 -04:00
|
|
|
(cond
|
|
|
|
((nonzero? parent)
|
|
|
|
(set! (-> child exit) (-> parent exit))
|
|
|
|
(set! (-> child code) (-> parent code))
|
|
|
|
(set! (-> child trans) (-> parent trans))
|
|
|
|
(set! (-> child post) (-> parent post))
|
|
|
|
(set! (-> child enter) (-> parent enter))
|
|
|
|
(set! (-> child event) (-> parent event))
|
|
|
|
)
|
|
|
|
(else
|
|
|
|
;; Note: this is added to let us defstate on a child before the parent.
|
2021-12-04 15:34:03 -05:00
|
|
|
;; The child won't be usable like this, but it will prevent a crash.
|
2021-08-17 20:54:03 -04:00
|
|
|
(format 0 "[STATE ERROR] inherit-state got a null parent state. Child is ~A~%" (-> child name))
|
|
|
|
)
|
|
|
|
)
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-02-16 20:37:48 -05:00
|
|
|
child
|
|
|
|
)
|
|
|
|
|
|
|
|
(defmethod print state ((obj state))
|
|
|
|
"Print a state."
|
|
|
|
(format '#t "#<~A ~A @ #x~X>" (-> obj type) (-> obj name) obj)
|
|
|
|
obj
|
|
|
|
)
|
|
|
|
|
|
|
|
(define-extern enter-state (function object object object object object object object))
|
|
|
|
(defun enter-state (arg0 arg1 arg2 arg3 arg4 arg5)
|
|
|
|
"Make the process stored in pp enter the state in pp next-state"
|
|
|
|
;;(declare (print-asm))
|
|
|
|
(with-pp
|
|
|
|
;; unsleep us
|
|
|
|
(process-mask-clear! (-> pp mask) sleep sleep-code)
|
|
|
|
;; mark as going
|
|
|
|
(process-mask-set! (-> pp mask) going)
|
|
|
|
(cond
|
|
|
|
((= (-> pp status) 'initialize)
|
|
|
|
;; did a go during initialize.
|
|
|
|
;; remove the old trans hook, if there was one
|
|
|
|
(set! (-> pp trans-hook) #f)
|
|
|
|
(set-to-run (-> pp main-thread) enter-state arg0 arg1 arg2 arg3 arg4 arg5)
|
|
|
|
;; tell the kernel that we did a go during init
|
|
|
|
(set! (-> pp status) 'initialize-go)
|
|
|
|
;; abandon this thread, go back to what initialized us!
|
|
|
|
(throw 'initialize #t)
|
|
|
|
#t
|
|
|
|
)
|
|
|
|
((!= (-> *kernel-context* current-process) pp)
|
|
|
|
;; we aren't actually in process pp right now.
|
|
|
|
;; so set us up to go in the next run
|
|
|
|
(let ((status-backup (-> pp status)))
|
|
|
|
(set! (-> pp trans-hook) #f)
|
|
|
|
;; will set waiting-to-run
|
|
|
|
(set-to-run (-> pp main-thread) enter-state arg0 arg1 arg2 arg3 arg4 arg5)
|
|
|
|
;; restore the old status.
|
|
|
|
(set! (-> pp status) status-backup)
|
|
|
|
#t
|
|
|
|
)
|
|
|
|
)
|
|
|
|
((= (-> pp main-thread) (-> pp top-thread))
|
|
|
|
;; we are in the right process, and in the main thread!
|
|
|
|
;; actually do a go!
|
|
|
|
(set! (-> pp state) (-> pp next-state))
|
|
|
|
|
|
|
|
;; loop through current stack frames
|
|
|
|
(let ((frame (-> pp stack-frame-top)))
|
|
|
|
(while frame
|
2021-12-04 15:34:03 -05:00
|
|
|
(case (-> frame type)
|
2021-07-11 16:35:25 -04:00
|
|
|
((protect-frame state)
|
|
|
|
((-> (the-as protect-frame frame) exit))
|
|
|
|
)
|
2021-02-16 20:37:48 -05:00
|
|
|
)
|
|
|
|
(set! frame (-> frame next))
|
|
|
|
)
|
|
|
|
)
|
2021-12-04 15:34:03 -05:00
|
|
|
|
2021-02-16 20:37:48 -05:00
|
|
|
;; done with going!
|
|
|
|
(process-mask-clear! (-> pp mask) going)
|
|
|
|
|
|
|
|
;; now, update the process:
|
|
|
|
(let ((new-state (-> pp state)))
|
|
|
|
;; event hook from the current state
|
|
|
|
(set! (-> pp event-hook) (-> new-state event))
|
|
|
|
;; if we have an exit, push it onto the stack frame
|
|
|
|
;; and also blow away the old stack frame
|
|
|
|
(if (-> new-state exit)
|
|
|
|
(set! (-> pp stack-frame-top) new-state)
|
|
|
|
(set! (-> pp stack-frame-top) #f)
|
|
|
|
)
|
|
|
|
(set! (-> pp post-hook) (-> new-state post))
|
|
|
|
(set! (-> pp trans-hook) (-> new-state trans))
|
|
|
|
;; now do the enter
|
|
|
|
(let ((enter-func (-> new-state enter)))
|
|
|
|
(if enter-func
|
2021-08-17 20:54:03 -04:00
|
|
|
((the (function _varargs_ none) enter-func) arg0 arg1 arg2 arg3 arg4 arg5)
|
2021-02-16 20:37:48 -05:00
|
|
|
)
|
|
|
|
)
|
|
|
|
;; now do the trans
|
|
|
|
(let ((trans-func (-> new-state trans)))
|
|
|
|
(if trans-func
|
|
|
|
(trans-func)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
;; now we run the code, but in a tricky way.
|
|
|
|
(rlet ((temp)
|
|
|
|
(func)
|
|
|
|
(sp :reg rsp :type uint)
|
|
|
|
(off :reg r15 :type uint)
|
|
|
|
(carg0 :reg rdi)
|
|
|
|
(carg1 :reg rsi)
|
|
|
|
(carg2 :reg rdx)
|
|
|
|
(carg3 :reg rcx))
|
|
|
|
;; prepare args
|
|
|
|
;; compiler will likely have these on the stack, we need to get them in regs
|
|
|
|
;; before messing with the stack.
|
|
|
|
(.mov carg0 arg0)
|
|
|
|
(.mov carg1 arg1)
|
|
|
|
(.mov carg2 arg2)
|
|
|
|
(.mov carg3 arg3)
|
|
|
|
|
|
|
|
;; get the main code as an x86-64 pointer
|
|
|
|
(.mov func (-> new-state code))
|
|
|
|
(.add func off)
|
|
|
|
;; reset the stack (scary)
|
|
|
|
(.mov sp (-> pp main-thread stack-top))
|
|
|
|
(.add sp off)
|
|
|
|
;; push the return trampoline for when code returns.
|
|
|
|
(.mov temp return-from-thread-dead)
|
|
|
|
(.add temp off)
|
|
|
|
(.push temp)
|
|
|
|
;; and call!
|
|
|
|
(.jr func)
|
|
|
|
;; stupid hack so the compiler doesn't throw away these registers.
|
|
|
|
(.add carg0 carg1)
|
|
|
|
(.add carg2 carg3)
|
|
|
|
#f ;; can't get here
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
(else
|
|
|
|
;; not in the main-thread.
|
|
|
|
;; so we set up the main thread to try again.
|
|
|
|
(set! (-> pp trans-hook) #f)
|
|
|
|
(set-to-run (-> pp main-thread)
|
|
|
|
enter-state arg0 arg1 arg2 arg3 arg4 arg5)
|
|
|
|
(when (!= (-> pp top-thread name) 'post)
|
|
|
|
;; abandon this one too.
|
|
|
|
;; NOTE - this is different from GOAL.
|
|
|
|
;; GOAL installs this as the return address for this function and returns normally.
|
|
|
|
;; but we don't because I don't have an easy way to find where to stick this.
|
|
|
|
;; I can't see how this makes a difference, as all non-main threads seem
|
|
|
|
;; temporary, but if this turns out to be false, we will need to change this.
|
|
|
|
(rlet ((temp)
|
|
|
|
(off :reg r15 :type uint :reset-here #t))
|
|
|
|
(.mov temp return-from-thread)
|
|
|
|
(.add temp off)
|
|
|
|
(.push temp)
|
|
|
|
(.ret)
|
|
|
|
#f ;; can't get here
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2021-10-23 10:41:11 -04:00
|
|
|
(defun send-event-function ((proc process-tree) (msg event-message-block))
|
2021-07-23 18:30:49 -04:00
|
|
|
"Function to send an event to a process. Please use the send-event macros when possible"
|
|
|
|
|
2021-02-16 20:37:48 -05:00
|
|
|
(with-pp
|
2021-10-23 10:41:11 -04:00
|
|
|
(when (and proc (!= (-> proc type) process-tree) (-> (the process proc) event-hook))
|
2021-02-16 20:37:48 -05:00
|
|
|
(let ((pp-backup pp))
|
2021-10-23 10:41:11 -04:00
|
|
|
(set! pp (the process proc))
|
|
|
|
(let ((result ((-> (the process proc) event-hook) (-> msg from) (-> msg num-params) (-> msg message) msg)))
|
2021-02-16 20:37:48 -05:00
|
|
|
(set! pp pp-backup)
|
|
|
|
result
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2022-04-18 18:31:59 -04:00
|
|
|
(defmacro send-event (proc msg &key (from (with-pp pp)) &rest params)
|
2021-07-23 18:30:49 -04:00
|
|
|
"Send an event to a process. This should be used over send-event-function"
|
|
|
|
|
2022-04-18 18:31:59 -04:00
|
|
|
`(let ((event-data (new 'stack-no-clear 'event-message-block)))
|
|
|
|
(set! (-> event-data from) ,from)
|
2021-06-29 20:30:52 -04:00
|
|
|
(set! (-> event-data num-params) ,(length params))
|
|
|
|
(set! (-> event-data message) ,msg)
|
2021-11-13 22:41:15 -05:00
|
|
|
,@(apply-i (lambda (x i) `(set! (-> event-data param ,i) (the-as uint ,x))) params)
|
2021-06-29 20:30:52 -04:00
|
|
|
(send-event-function ,proc event-data)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2021-02-16 20:37:48 -05:00
|
|
|
(defun looping-code ()
|
|
|
|
"Loop."
|
2021-07-25 00:23:30 -04:00
|
|
|
(loop
|
2021-02-16 20:37:48 -05:00
|
|
|
(suspend)
|
|
|
|
)
|
|
|
|
#f
|
|
|
|
)
|
2021-07-25 00:23:30 -04:00
|
|
|
|
2021-08-16 02:44:05 -04:00
|
|
|
(defmacro set-state-time ()
|
|
|
|
"set the state-time field of the current object to the current time. process-drawable has one"
|
2021-07-25 00:23:30 -04:00
|
|
|
|
2021-08-16 02:44:05 -04:00
|
|
|
`(set! (-> self state-time) (current-time))
|
|
|
|
)
|
|
|
|
|
|
|
|
(defmacro time-passed ()
|
|
|
|
"how much time has passed since set-state-time"
|
|
|
|
`(- (current-time) (-> self state-time))
|
|
|
|
)
|
|
|
|
|
|
|
|
(defmacro time-passed? (time)
|
|
|
|
"has it been 'time' since set-state-time?"
|
|
|
|
`(>= (time-passed) ,time)
|
|
|
|
)
|
2021-07-25 00:23:30 -04:00
|
|
|
|
|
|
|
|
|
|
|
|