;;;-*- Mode: Lisp; Package: CCL -*- ;;; ;;; Copyright (C) 2009 Clozure Associates ;;; Copyright (C) 1994-2001 Digitool, Inc ;;; This file is part of Clozure CL. ;;; ;;; Clozure CL is licensed under the terms of the Lisp Lesser GNU Public ;;; License , known as the LLGPL and distributed with Clozure CL as the ;;; file "LICENSE". The LLGPL consists of a preamble and the LGPL, ;;; which is distributed with Clozure CL as the file "LGPL". Where these ;;; conflict, the preamble takes precedence. ;;; ;;; Clozure CL is referenced in the preamble as the "LIBRARY." ;;; ;;; The LLGPL is also available online at ;;; http://opensource.franz.com/preamble.html ;;; l1-callbacks.lisp (in-package "CCL") (defstatic *callback-lock* (make-lock)) ;;; (defcallback ...) expands into a call to this function. (defun define-callback-function (lisp-function &optional doc-string (without-interrupts t) info &aux name trampoline) (unless (functionp lisp-function) (setq lisp-function (require-type lisp-function 'function))) (unless (and (symbolp (setq name (function-name lisp-function))) ;;Might as well err out now before do any _Newptr's... (not (constant-symbol-p name))) (report-bad-arg name '(and symbol (not (satisfies constantp))))) (with-lock-grabbed (*callback-lock*) (let ((len (length %pascal-functions%))) (declare (fixnum len)) (when (and name (boundp name)) (let ((old-tramp (symbol-value name))) (dotimes (i len) (let ((pfe (%svref %pascal-functions% i))) (when (and (vectorp pfe) (eql old-tramp (pfe.routine-descriptor pfe))) (setf (pfe.without-interrupts pfe) without-interrupts) (setf (pfe.lisp-function pfe) lisp-function) (setq trampoline old-tramp)))))) (unless trampoline (let ((index (dotimes (i (length %pascal-functions%) (let* ((new-len (if (zerop len) 32 (* len 2))) (new-pf (make-array (the fixnum new-len)))) (declare (fixnum new-len)) (dotimes (i len) (setf (%svref new-pf i) (%svref %pascal-functions% i))) (do ((i len (1+ i))) ((>= i new-len)) (declare (fixnum i)) (setf (%svref new-pf i) nil)) (setq %pascal-functions% new-pf) len)) (unless (%svref %pascal-functions% i) (return i))))) (setq trampoline (make-callback-trampoline index info)) (setf (%svref %pascal-functions% index) (%cons-pfe trampoline info lisp-function name without-interrupts)))))) ;;(%proclaim-special name) ; ;; already done by defpascal expansion (when name (set name trampoline)) (record-source-file name 'callback) (when (and doc-string *save-doc-strings*) (setf (documentation name 'variable) doc-string)) (when *fasload-print* (format t "~&~S~%" name)) (or name trampoline)) (defun %lookup-pascal-function (index) (declare (optimize (speed 3) (safety 0))) (with-lock-grabbed (*callback-lock*) (let* ((pfe (svref %pascal-functions% index))) (values (pfe.lisp-function pfe) (pfe.without-interrupts pfe) (pfe.trace-p pfe))))) (defun %callback-function (pointer) (if (typep pointer 'symbol) (setq pointer (symbol-value pointer))) (with-lock-grabbed (*callback-lock*) (let* ((index (dotimes (i (length %pascal-functions%)) (when (eql (pfe.routine-descriptor (svref %pascal-functions% i)) pointer) (return i))))) (when index (let* ((entry (svref %pascal-functions% index))) (pfe.lisp-function entry)))))) (defun %delete-pascal-function (pointer) (with-lock-grabbed (*callback-lock*) (let* ((index (dotimes (i (length %pascal-functions%)) (when (eql (pfe.routine-descriptor (svref %pascal-functions% i)) pointer) (return i))))) (when index (let* ((entry (svref %pascal-functions% index)) (sym (pfe.sym entry))) (setf (svref %pascal-functions% index) nil) (when (and sym (boundp sym) (eql (symbol-value sym) (pfe.routine-descriptor entry))) (set (symbol-value sym) nil)) (free (pfe.routine-descriptor entry)) t))))) ;; The kernel only really knows how to call back to one function, ;; and you're looking at it ... (defun %pascal-functions% (index args-ptr-fixnum) (declare (optimize (speed 3) (safety 0))) (multiple-value-bind (lisp-function without-interrupts *callback-trace-p*) (%lookup-pascal-function index) (declare (special *callback-trace-p*)) (if without-interrupts (without-interrupts (funcall lisp-function args-ptr-fixnum)) (funcall lisp-function args-ptr-fixnum)))) (defstatic *callback-alloc-lock* (make-lock)) ;;; (defun %make-executable-page () #-windows-target (#_mmap (%null-ptr) #-android-target (#_getpagesize) #+android-target (#_sysconf #$_SC_PAGE_SIZE) (logior #$PROT_READ #$PROT_WRITE #$PROT_EXEC) (logior #$MAP_PRIVATE #$MAP_ANON) -1 0) #+windows-target (#_VirtualAlloc (%null-ptr) (ash 1 16) ; should use GetSystemInfo (logior #$MEM_RESERVE #$MEM_COMMIT) #$PAGE_EXECUTE_READWRITE) ) (defstatic *available-bytes-for-callbacks* 0) (defstatic *current-callback-page* nil) (defun reset-callback-storage () (setq *available-bytes-for-callbacks* #-windows-target #-android-target (#_getpagesize) #+android-target (#_sysconf #$_SC_PAGE_SIZE) #+windows-target (ash 1 16) *current-callback-page* (%make-executable-page))) (defun %allocate-callback-pointer (n) (with-lock-grabbed (*callback-alloc-lock*) (when (< *available-bytes-for-callbacks* n) (reset-callback-storage)) (decf *available-bytes-for-callbacks* n) (values (%inc-ptr *current-callback-page* *available-bytes-for-callbacks*))))