1.0.5.49: interrupt & GC & PA handling
[sbcl.git] / src / code / sysmacs.lisp
1 ;;;; miscellaneous system hacking macros
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!IMPL")
13
14 (defmacro atomic-incf/symbol (symbol-name &optional (delta 1))
15   #!-sb-thread
16   `(incf ,symbol-name ,delta)
17   #!+sb-thread
18   `(locally
19     (declare (optimize (safety 0) (speed 3)))
20     (sb!vm::locked-symbol-global-value-add ',symbol-name ,delta)))
21
22 (defvar *gc-inhibit*) ; initialized in cold init
23
24 ;;; When the dynamic usage increases beyond this amount, the system
25 ;;; notes that a garbage collection needs to occur by setting
26 ;;; *GC-PENDING* to T. It starts out as NIL meaning nobody has figured
27 ;;; out what it should be yet.
28 (defvar *gc-pending* nil)
29
30 #!+sb-thread
31 (defvar *stop-for-gc-pending* nil)
32
33 (defmacro without-gcing (&body body)
34   #!+sb-doc
35   "Executes the forms in the body without doing a garbage collection. It
36 inhibits both automatically and explicitly triggered collections. Finally,
37 upon leaving the BODY if gc is not inhibited it runs the pending gc.
38 Similarly, if gc is triggered in another thread then it waits until gc is
39 enabled in this thread.
40
41 Implies SB-SYS:WITHOUT-INTERRUPTS for BODY, and causes any nested
42 SB-SYS:WITH-INTERRUPTS to signal a warning during execution of the BODY.
43
44 Should be used with great care, and not at all in multithreaded application
45 code: Any locks that are ever acquired while GC is inhibited need to be always
46 held with GC inhibited to prevent deadlocks: if T1 holds the lock and is
47 stopped for GC while T2 is waiting for the lock inside WITHOUT-GCING the
48 system will be deadlocked. Since SBCL does not currently document its internal
49 locks, application code can never be certain that this invariant is
50 maintained."
51   (with-unique-names (without-gcing-body)
52     `(flet ((,without-gcing-body ()
53               ,@body))
54        (if *gc-inhibit*
55            (,without-gcing-body)
56            (without-interrupts
57              ;; We need to disable interrupts before disabling GC, so that
58              ;; signal handlers using locks don't accidentally try to grab
59              ;; them with GC inhibited.
60              ;;
61              ;; It would be nice to implement this with just a single UWP, but
62              ;; unfortunately it seems that it cannot be done: the naive
63              ;; solution of binding both *INTERRUPTS-ENABLED* and
64              ;; *GC-INHIBIT*, and checking for both pending GC and interrupts
65              ;; in the cleanup breaks if we have a GC pending, but no
66              ;; interrupts, and we receive an asynch unwind while checking for
67              ;; the pending GC: we unwind before handling the pending GC, and
68              ;; will be left running with further GCs blocked due to the GC
69              ;; pending flag.
70              (unwind-protect
71                   (let ((*gc-inhibit* t))
72                     (,without-gcing-body))
73                (when (or *gc-pending* #!+sb-thread *stop-for-gc-pending*)
74                  (sb!unix::receive-pending-interrupt))))))))
75
76 \f
77 ;;; EOF-OR-LOSE is a useful macro that handles EOF.
78 (defmacro eof-or-lose (stream eof-error-p eof-value)
79   `(if ,eof-error-p
80        (error 'end-of-file :stream ,stream)
81        ,eof-value))
82
83 ;;; These macros handle the special cases of T and NIL for input and
84 ;;; output streams.
85 ;;;
86 ;;; FIXME: Shouldn't these be functions instead of macros?
87 (defmacro in-synonym-of (stream &optional check-type)
88   (let ((svar (gensym)))
89     `(let ((,svar ,stream))
90        (cond ((null ,svar) *standard-input*)
91              ((eq ,svar t) *terminal-io*)
92              (t ,@(when check-type `((enforce-type ,svar ,check-type))) ;
93                 #!+high-security
94                 (unless (input-stream-p ,svar)
95                   (error 'simple-type-error
96                          :datum ,svar
97                          :expected-type '(satisfies input-stream-p)
98                          :format-control "~S isn't an input stream"
99                          :format-arguments (list ,svar)))
100                 ,svar)))))
101 (defmacro out-synonym-of (stream &optional check-type)
102   (let ((svar (gensym)))
103     `(let ((,svar ,stream))
104        (cond ((null ,svar) *standard-output*)
105              ((eq ,svar t) *terminal-io*)
106              (t ,@(when check-type `((check-type ,svar ,check-type)))
107                 #!+high-security
108                 (unless (output-stream-p ,svar)
109                   (error 'simple-type-error
110                          :datum ,svar
111                          :expected-type '(satisfies output-stream-p)
112                          :format-control "~S isn't an output stream."
113                          :format-arguments (list ,svar)))
114                 ,svar)))))
115
116 ;;; WITH-mumble-STREAM calls the function in the given SLOT of the
117 ;;; STREAM with the ARGS for ANSI-STREAMs, or the FUNCTION with the
118 ;;; ARGS for FUNDAMENTAL-STREAMs.
119 (defmacro with-in-stream (stream (slot &rest args) &optional stream-dispatch)
120   `(let ((stream (in-synonym-of ,stream)))
121     ,(if stream-dispatch
122          `(if (ansi-stream-p stream)
123               (funcall (,slot stream) stream ,@args)
124               ,@(when stream-dispatch
125                   `(,(destructuring-bind (function &rest args) stream-dispatch
126                        `(,function stream ,@args)))))
127          `(funcall (,slot stream) stream ,@args))))
128
129 (defmacro with-out-stream/no-synonym (stream (slot &rest args) &optional stream-dispatch)
130   `(let ((stream ,stream))
131     ,(if stream-dispatch
132          `(if (ansi-stream-p stream)
133               (funcall (,slot stream) stream ,@args)
134               ,@(when stream-dispatch
135                   `(,(destructuring-bind (function &rest args) stream-dispatch
136                                          `(,function stream ,@args)))))
137          `(funcall (,slot stream) stream ,@args))))
138
139 (defmacro with-out-stream (stream (slot &rest args) &optional stream-dispatch)
140   `(with-out-stream/no-synonym (out-synonym-of ,stream)
141     (,slot ,@args) ,stream-dispatch))
142
143 \f
144 ;;;; These are hacks to make the reader win.
145
146 ;;; This macro sets up some local vars for use by the
147 ;;; FAST-READ-CHAR macro within the enclosed lexical scope. The stream
148 ;;; is assumed to be a ANSI-STREAM.
149 ;;;
150 ;;; KLUDGE: Some functions (e.g. ANSI-STREAM-READ-LINE) use these variables
151 ;;; directly, instead of indirecting through FAST-READ-CHAR.
152 (defmacro prepare-for-fast-read-char (stream &body forms)
153   `(let* ((%frc-stream% ,stream)
154           (%frc-method% (ansi-stream-in %frc-stream%))
155           (%frc-buffer% (ansi-stream-cin-buffer %frc-stream%))
156           (%frc-index% (ansi-stream-in-index %frc-stream%)))
157      (declare (type index %frc-index%)
158               (type ansi-stream %frc-stream%))
159      ,@forms))
160
161 ;;; This macro must be called after one is done with FAST-READ-CHAR
162 ;;; inside its scope to decache the ANSI-STREAM-IN-INDEX.
163 (defmacro done-with-fast-read-char ()
164   `(setf (ansi-stream-in-index %frc-stream%) %frc-index%))
165
166 ;;; a macro with the same calling convention as READ-CHAR, to be used
167 ;;; within the scope of a PREPARE-FOR-FAST-READ-CHAR.
168 (defmacro fast-read-char (&optional (eof-error-p t) (eof-value ()))
169   `(cond
170     ((not %frc-buffer%)
171      (funcall %frc-method% %frc-stream% ,eof-error-p ,eof-value))
172     ((= %frc-index% +ansi-stream-in-buffer-length+)
173      (prog1 (fast-read-char-refill %frc-stream% ,eof-error-p ,eof-value)
174             (setq %frc-index% (ansi-stream-in-index %frc-stream%))))
175     (t
176      (prog1 (aref %frc-buffer% %frc-index%)
177             (incf %frc-index%)))))
178
179 ;;;; And these for the fasloader...
180
181 ;;; Just like PREPARE-FOR-FAST-READ-CHAR except that we get the BIN
182 ;;; method. The stream is assumed to be a ANSI-STREAM.
183 ;;;
184 ;;; KLUDGE: It seems weird to have to remember to explicitly call
185 ;;; DONE-WITH-FAST-READ-BYTE at the end of this, given that we're
186 ;;; already wrapping the stuff inside in a block. Why not rename this
187 ;;; macro to WITH-FAST-READ-BYTE, do the DONE-WITH-FAST-READ-BYTE stuff
188 ;;; automatically at the end of the block, and eliminate
189 ;;; DONE-WITH-FAST-READ-BYTE as a separate entity? (and similarly
190 ;;; for the FAST-READ-CHAR stuff) -- WHN 19990825
191 (defmacro prepare-for-fast-read-byte (stream &body forms)
192   `(let* ((%frc-stream% ,stream)
193           (%frc-method% (ansi-stream-bin %frc-stream%))
194           (%frc-buffer% (ansi-stream-in-buffer %frc-stream%))
195           (%frc-index% (ansi-stream-in-index %frc-stream%)))
196      (declare (type index %frc-index%)
197               (type ansi-stream %frc-stream%))
198      ,@forms))
199
200 ;;; Similar to fast-read-char, but we use a different refill routine & don't
201 ;;; convert to characters. If ANY-TYPE is true, then this can be used on any
202 ;;; integer streams, and we don't assert the result type.
203 (defmacro fast-read-byte (&optional (eof-error-p t) (eof-value ()) any-type)
204   ;; KLUDGE: should use ONCE-ONLY on EOF-ERROR-P and EOF-VALUE -- WHN 19990825
205   `(truly-the
206     ,(if (and (eq eof-error-p t) (not any-type)) '(unsigned-byte 8) t)
207     (cond
208      ((not %frc-buffer%)
209       (funcall %frc-method% %frc-stream% ,eof-error-p ,eof-value))
210      ((= %frc-index% +ansi-stream-in-buffer-length+)
211       (prog1 (fast-read-byte-refill %frc-stream% ,eof-error-p ,eof-value)
212         (setq %frc-index% (ansi-stream-in-index %frc-stream%))))
213      (t
214       (prog1 (aref %frc-buffer% %frc-index%)
215         (incf %frc-index%))))))
216 (defmacro done-with-fast-read-byte ()
217   `(done-with-fast-read-char))