home *** CD-ROM | disk | FTP | other *** search
- ;;; -*- Mode: common-lisp; Package: xlib; Base: 10; Lowercase: Yes -*-
- ;;;
- ;;; CLX -- excldep.cl
- ;;;
- ;;; Copyright (c) 1987, 1988, 1989 Franz Inc, Berkeley, Ca.
- ;;;
- ;;; Permission is granted to any individual or institution to use, copy,
- ;;; modify, and distribute this software, provided that this complete
- ;;; copyright and permission notice is maintained, intact, in all copies and
- ;;; supporting documentation.
- ;;;
- ;;; Franz Incorporated provides this software "as is" without
- ;;; express or implied warranty.
- ;;;
-
- (in-package :xlib)
-
- (eval-when (compile load eval)
- (require :foreign)
- (require :process) ; Needed even if scheduler is not
- ; running. (Must be able to make
- ; a process-lock.)
- )
-
- (eval-when (load)
- (provide :clx))
-
-
- #-(or little-endian big-endian)
- (eval-when (eval compile load)
- (let ((x '#(1)))
- (if (not (eq 0 (sys::memref x
- #.(comp::mdparam 'comp::md-svector-data0-adj)
- 0 :unsigned-byte)))
- (pushnew :little-endian *features*)
- (pushnew :big-endian *features*))))
-
-
- (defmacro correct-case (string)
- ;; This macro converts the given string to the
- ;; current preferred case, or leaves it alone in a case-sensitive mode.
- (let ((str (gensym)))
- `(let ((,str ,string))
- (case excl::*current-case-mode*
- (:case-insensitive-lower
- (string-downcase ,str))
- (:case-insensitive-upper
- (string-upcase ,str))
- ((:case-sensitive-lower :case-sensitive-upper)
- ,str)))))
-
-
- (defconstant type-pred-alist
- '(#-(version>= 4 1 devel 16)
- (card8 . card8p)
- #-(version>= 4 1 devel 16)
- (card16 . card16p)
- #-(version>= 4 1 devel 16)
- (card29 . card29p)
- #-(version>= 4 1 devel 16)
- (card32 . card32p)
- #-(version>= 4 1 devel 16)
- (int8 . int8p)
- #-(version>= 4 1 devel 16)
- (int16 . int16p)
- #-(version>= 4 1 devel 16)
- (int32 . int32p)
- #-(version>= 4 1 devel 16)
- (mask16 . card16p)
- #-(version>= 4 1 devel 16)
- (mask32 . card32p)
- #-(version>= 4 1 devel 16)
- (pixel . card32p)
- #-(version>= 4 1 devel 16)
- (resource-id . card29p)
- #-(version>= 4 1 devel 16)
- (keysym . card32p)
- (angle . anglep)
- (color . color-p)
- (bitmap-format . bitmap-format-p)
- (pixmap-format . pixmap-format-p)
- (display . display-p)
- (drawable . drawable-p)
- (window . window-p)
- (pixmap . pixmap-p)
- (visual-info . visual-info-p)
- (colormap . colormap-p)
- (cursor . cursor-p)
- (gcontext . gcontext-p)
- (screen . screen-p)
- (font . font-p)
- (image-x . image-x-p)
- (image-xy . image-xy-p)
- (image-z . image-z-p)
- (wm-hints . wm-hints-p)
- (wm-size-hints . wm-size-hints-p)
- ))
-
- ;; This (if (and ...) t nil) stuff has a purpose -- it lets the old
- ;; sun4 compiler opencode the `and'.
-
- #-(version>= 4 1 devel 16)
- (defun card8p (x)
- (declare (optimize (speed 3) (safety 0))
- (fixnum x))
- (if (and (excl:fixnump x) (> #.(expt 2 8) x) (>= x 0))
- t
- nil))
-
- #-(version>= 4 1 devel 16)
- (defun card16p (x)
- (declare (optimize (speed 3) (safety 0))
- (fixnum x))
- (if (and (excl:fixnump x) (> #.(expt 2 16) x) (>= x 0))
- t
- nil))
-
- #-(version>= 4 1 devel 16)
- (defun card29p (x)
- (declare (optimize (speed 3) (safety 0)))
- (if (or (and (excl:fixnump x) (>= (the fixnum x) 0))
- (and (excl:bignump x) (> #.(expt 2 29) (the bignum x))
- (>= (the bignum x) 0)))
- t
- nil))
-
- #-(version>= 4 1 devel 16)
- (defun card32p (x)
- (declare (optimize (speed 3) (safety 0)))
- (if (or (and (excl:fixnump x) (>= (the fixnum x) 0))
- (and (excl:bignump x) (> #.(expt 2 32) (the bignum x))
- (>= (the bignum x) 0)))
- t
- nil))
-
- #-(version>= 4 1 devel 16)
- (defun int8p (x)
- (declare (optimize (speed 3) (safety 0))
- (fixnum x))
- (if (and (excl:fixnump x) (> #.(expt 2 7) x) (>= x #.(expt -2 7)))
- t
- nil))
-
- #-(version>= 4 1 devel 16)
- (defun int16p (x)
- (declare (optimize (speed 3) (safety 0))
- (fixnum x))
- (if (and (excl:fixnump x) (> #.(expt 2 15) x) (>= x #.(expt -2 15)))
- t
- nil))
-
- #-(version>= 4 1 devel 16)
- (defun int32p (x)
- (declare (optimize (speed 3) (safety 0)))
- (if (or (excl:fixnump x)
- (and (excl:bignump x) (> #.(expt 2 31) (the bignum x))
- (>= (the bignum x) #.(expt -2 31))))
- t
- nil))
-
- ;; This one can be handled better by knowing a little about what we're
- ;; testing for. Plus this version can handle (single-float pi), which
- ;; is otherwise larger than pi!
- (defun anglep (x)
- (declare (optimize (speed 3) (safety 0)))
- (if (or (and (excl::fixnump x) (>= (the fixnum x) #.(truncate (* -2 pi)))
- (<= (the fixnum x) #.(truncate (* 2 pi))))
- (and (excl::single-float-p x)
- (>= (the single-float x) #.(float (* -2 pi) 0.0s0))
- (<= (the single-float x) #.(float (* 2 pi) 0.0s0)))
- (and (excl::double-float-p x)
- (>= (the double-float x) #.(float (* -2 pi) 0.0d0))
- (<= (the double-float x) #.(float (* 2 pi) 0.0d0))))
- t
- nil))
-
- (eval-when (load eval)
- #+(version>= 4 1 devel 16)
- (mapcar #'(lambda (elt) (excl:add-typep-transformer (car elt) (cdr elt)))
- type-pred-alist)
- #-(version>= 4 1 devel 16)
- (nconc excl::type-pred-alist type-pred-alist))
-
-
- ;; Return t if there is a character available for reading or on error,
- ;; otherwise return nil.
- (defun fd-char-avail-p (fd)
- (multiple-value-bind (available-p errcode)
- (comp::.primcall-sargs 'sys::filesys excl::fs-char-avail fd)
- (excl:if* errcode
- then t
- else available-p)))
-
- (defmacro with-interrupt-checking-on (&body body)
- `(locally (declare (optimize (safety 1)))
- ,@body))
-
- ;; Read from the given fd into 'vector', which has element type card8.
- ;; Start storing at index 'start-index' and read exactly 'length' bytes.
- ;; Return t if an error or eof occurred, nil otherwise.
- (defun fd-read-bytes (fd vector start-index length)
- (declare (fixnum fd start-index length)
- (type (simple-array (unsigned-byte 8) (*)) vector))
- (with-interrupt-checking-on
- (do ((rest length))
- ((eq 0 rest) nil)
- (declare (fixnum rest))
- (multiple-value-bind (numread errcode)
- (comp::.primcall-sargs 'sys::filesys excl::fs-read-bytes fd vector
- start-index rest)
- (declare (fixnum numread))
- (excl:if* errcode
- then (if (not (eq errcode
- excl::*error-code-interrupted-system-call*))
- (return t))
- elseif (eq 0 numread)
- then (return t)
- else (decf rest numread)
- (incf start-index numread))))))
-
-
- (when (plusp (ff:get-entry-points
- (make-array 1 :initial-contents
- (list (ff:convert-to-lang "fd_wait_for_input")))
- (make-array 1 :element-type '(unsigned-byte 32))))
- (ff:remove-entry-point (ff:convert-to-lang "fd_wait_for_input"))
- (load "excldep.o"))
-
- (when (plusp (ff:get-entry-points
- (make-array 1 :initial-contents
- (list (ff:convert-to-lang "connect_to_server")))
- (make-array 1 :element-type '(unsigned-byte 32))))
- (ff:remove-entry-point (ff:convert-to-lang "connect_to_server" :language :c))
- (load "socket.o"))
-
- (ff:defforeign-list `((connect-to-server
- :entry-point
- ,(ff:convert-to-lang "connect_to_server")
- :return-type :fixnum
- :arg-checking nil
- :arguments (string fixnum))
- (fd-wait-for-input
- :entry-point ,(ff:convert-to-lang "fd_wait_for_input")
- :return-type :fixnum
- :arg-checking nil
- :call-direct t
- :callback nil
- :allow-other-keys t
- :arguments (fixnum fixnum))))
-
-
- ;; special patch for CLX (various process fixes)
- ;; patch1000.2
-
- (eval-when (compile load eval)
- (unless (find-package :patch)
- (make-package :patch :use '(:lisp :excl))))
-
- (in-package :patch)
-
- (defvar *patches* nil)
-
- #+allegro
- (eval-when (compile eval load)
- (when (and (= excl::cl-major-version-number 3)
- (or (= excl::cl-minor-version-number 0)
- (and (= excl::cl-minor-version-number 1)
- excl::cl-generation-number
- (< excl::cl-generation-number 9))))
- (push :clx-r4-process-patches *features*)))
-
- #+clx-r4-process-patches
- (push (cons 1000.2 "special patch for CLX (various process fixes)")
- *patches*)
-
-
- (in-package :mp)
-
- #+clx-r4-process-patches
- (export 'wait-for-input-available)
-
-
- #+clx-r4-process-patches
- (defun with-timeout-event (seconds fnc args)
- (unless *scheduler-stack-group* (start-scheduler)) ;[spr670]
- (let ((clock-event (make-clock-event)))
- (when (<= seconds 0) (setq seconds 0))
- (multiple-value-bind (secs msecs) (truncate seconds)
- ;; secs is now a nonegative integer, and msecs is either fixnum zero
- ;; or else something interesting.
- (unless (eq 0 msecs)
- (setq msecs (truncate (* 1000.0 msecs))))
- ;; Now msecs is also a nonnegative fixnum.
- (multiple-value-bind (now mnow) (excl::cl-internal-real-time)
- (incf secs now)
- (incf msecs mnow)
- (when (>= msecs 1000)
- (decf msecs 1000)
- (incf secs))
- (unless (excl:fixnump secs) (setq secs most-positive-fixnum))
- (setf (clock-event-secs clock-event) secs
- (clock-event-msecs clock-event) msecs
- (clock-event-function clock-event) fnc
- (clock-event-args clock-event) args)))
- clock-event))
-
-
- #+clx-r4-process-patches
- (defmacro with-timeout ((seconds &body timeout-body) &body body)
- `(let* ((clock-event (with-timeout-event ,seconds
- #'process-interrupt
- (cons *current-process*
- '(with-timeout-internal))))
- (excl::*without-interrupts* t)
- ret)
- (unwind-protect
- ;; Warning: Branch tensioner better not reorder this code!
- (setq ret (catch 'with-timeout-internal
- (add-to-clock-queue clock-event)
- (let ((excl::*without-interrupts* nil))
- (multiple-value-list (progn ,@body)))))
- (excl:if* (eq ret 'with-timeout-internal)
- then (let ((excl::*without-interrupts* nil))
- (setq ret (multiple-value-list (progn ,@timeout-body))))
- else (remove-from-clock-queue clock-event)))
- (values-list ret)))
-
-
- #+clx-r4-process-patches
- (defun process-lock (lock &optional (lock-value *current-process*)
- (whostate "Lock") timeout)
- (declare (optimize (speed 3)))
- (unless (process-lock-p lock)
- (error "First argument to PROCESS-LOCK must be a process-lock: ~s" lock))
- (without-interrupts
- (excl:if* (null (process-lock-locker lock))
- then (setf (process-lock-locker lock) lock-value)
- else (excl:if* timeout
- then (excl:if* (or (eq 0 timeout) ;for speed
- (zerop timeout))
- then nil
- else (with-timeout (timeout)
- (process-lock-1 lock lock-value whostate)))
- else (process-lock-1 lock lock-value whostate)))))
-
-
- #+clx-r4-process-patches
- (defun process-lock-1 (lock lock-value whostate)
- (declare (type process-lock lock)
- (optimize (speed 3)))
- (let ((process *current-process*))
- (declare (type process process))
- (unless process
- (error
- "PROCESS-LOCK may not be called on the scheduler's stack group."))
- (loop (unless (process-lock-locker lock)
- (return (setf (process-lock-locker lock) lock-value)))
- (push process (process-lock-waiting lock))
- (let ((saved-whostate (process-whostate process)))
- (unwind-protect
- (progn (setf (process-whostate process) whostate)
- (process-add-arrest-reason process lock))
- (setf (process-whostate process) saved-whostate))))))
-
-
- #+clx-r4-process-patches
- (defun process-wait (whostate function &rest args)
- (declare (optimize (speed 3)))
- ;; Run the wait function once here both for efficiency and as a
- ;; first line check for errors in the function.
- (unless (apply function args)
- (process-wait-1 whostate function args)))
-
-
- #+clx-r4-process-patches
- (defun process-wait-1 (whostate function args)
- (declare (optimize (speed 3)))
- (let ((process *current-process*))
- (declare (type process process))
- (unless process
- (error
- "Process-wait may not be called within the scheduler's stack group."))
- (let ((saved-whostate (process-whostate process)))
- (unwind-protect
- (without-scheduling-internal
- (without-interrupts
- (setf (process-whostate process) whostate
- (process-wait-function process) function
- (process-wait-args process) args)
- (chain-rem-q process)
- (chain-ins-q process *waiting-processes*))
- (process-resume-scheduler nil))
- (setf (process-whostate process) saved-whostate
- (process-wait-function process) nil
- (process-wait-args process) nil)))))
-
-
- #+clx-r4-process-patches
- (defun process-wait-with-timeout (whostate seconds function &rest args)
- ;; Now returns T upon completion, NIL upon timeout. -- 6Jun89 smh
- ;; [spr1135] [rfe939] Timeout won't throw out of interrupt level code.
- ;; -- 28Feb90 smh
- ;; Run the wait function once here both for efficiency and as a
- ;; first line check for errors in the function.
- (excl:if* (apply function args)
- then t
- else (let ((ret (list nil)))
- (without-interrupts
- (let ((clock-event
- (with-timeout-event seconds #'identity '(nil))))
- (add-to-clock-queue clock-event)
- (process-wait-1 whostate
- #'(lambda (clock-event function args ret)
- (or (null (chain-next clock-event))
- (and (apply function args)
- (setf (car ret) 't))))
- (list clock-event function args ret))))
- (car ret))))
-
-
- ;;
- ;; Returns nil on timeout, otherwise t.
- ;;
- #+clx-r4-process-patches
- (defun wait-for-input-available
- (stream-or-fd &key (wait-function #'listen)
- (whostate "waiting for input")
- timeout)
- (let ((fd (excl:if* (excl:fixnump stream-or-fd) then stream-or-fd
- elseif (streamp stream-or-fd)
- then (excl::stream-input-fn stream-or-fd)
- else (error "wait-for-input-available expects a stream or file descriptor: ~s" stream-or-fd))))
- ;; At this point fd could be nil, since stream-input-fn returns nil for
- ;; streams that are output only, or for certain special purpose streams.
- (if fd
- (unwind-protect
- (progn
- (mp::mpwatchfor fd)
- (excl:if* timeout
- then (mp::process-wait-with-timeout
- whostate timeout wait-function stream-or-fd)
- else (mp::process-wait whostate wait-function stream-or-fd)
- t))
- (mp::mpunwatchfor fd))
- (excl:if* timeout
- then (mp::process-wait-with-timeout
- whostate timeout wait-function stream-or-fd)
- else (mp::process-wait whostate wait-function stream-or-fd)
- t))))
-