forked from franzinc/clim2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprocesses.lisp
420 lines (380 loc) · 14.1 KB
/
processes.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Package: CLIM-UTILS; Base: 10; Lowercase: Yes -*-
;; See the file LICENSE for the full license governing this code.
;;
(in-package :clim-utils)
;;;"Copyright (c) 1990, 1991, 1992 Symbolics, Inc. All rights reserved.
;;; Portions copyright (c) 1988, 1989, 1990 International Lisp Associates.
;;; Portions copyright (c) 1992, 1993 Franz, Inc."
;;; Locks
(eval-when (compile load eval)
;;; (require :mdproc)
(require :process))
(defvar *multiprocessing-p*
#{
(or allegro Genera Lucid Lispworks Minima) t
otherwise nil
}
)
;;; This is to keep it quiet: On ACL it's safe to declare the
;;; predicate & args dynamic-extent on platforms with native threads
;;; *only*, which at present (6.0beta) is Windows platforms.
;;;
;;; the real definition of process-wait is in
;;; clim2:;aclpc;acl-clim.lisp. That definition is almost certainly
;;; bogus because it misunderstands the whole way multithreading
;;; works: the definition above should be used instead. But the
;;; Windows event-loop depends on this misunderstanding, and I don't
;;; want to change that.
;;;
#+(and allegro mswindows)
(excl:defun-proto process-wait (wait-reason predicate &rest args)
(declare (dynamic-extent predicate args)))
;;-- I dont think we need this
;#+Allegro
;(unless (excl::scheduler-running-p)
; (mp:start-scheduler))
(defmacro with-lock-held ((place &optional state) &body forms)
#+(or allegro Xerox Genera ccl Minima)
(declare (ignore state #+ccl place))
#{
allegro `(mp:with-process-lock (,place) ,@forms)
Lucid `(lcl:with-process-lock (,place ,@(if state (cons state nil)))
,@forms)
lispworks `(mp::with-lock (,place) ,@forms)
Xerox `(il:with.monitor ,place ,@forms)
Cloe-Runtime `(progn ,@forms)
aclpc `(progn ,@forms)
Genera `(process:with-lock (,place) ,@forms)
Minima `(minima:with-lock (,place) ,@forms)
CCL-2 `(progn ,@forms)
}
)
(defun make-lock (&optional (lock-name "a CLIM lock"))
#-(or Genera Minima allegro) (declare (ignore lock-name))
#{
allegro (mp::make-process-lock :name lock-name)
lispworks (mp::make-lock)
Lucid nil
CCL-2 nil
Xerox (il:create.monitorlock)
Cloe-Runtime nil
aclpc nil
Genera (process:make-lock lock-name)
Minima (minima:make-lock lock-name)
}
)
;;; A lock that CAN be relocked by the same process.
#-(or Genera Minima)
(defmacro with-simple-recursive-lock ((lock &optional (state "Unlock")) &body forms)
`(flet ((foo () ,@forms))
(declare (dynamic-extent #'foo))
(invoke-with-simple-recursive-lock ,lock ,state #'foo)))
#-(or Genera Minima)
(defun invoke-with-simple-recursive-lock (place state continuation)
(let ((store-value (current-process))
(place-value (first place)))
(if (and place-value (eql place-value store-value))
(funcall continuation)
(progn
(unless (null place-value)
(flet ((waiter ()
(null (first place))))
#-allegro (declare (dynamic-extent #'waiter))
(process-wait state #'waiter)))
(unwind-protect
(progn (rplaca place store-value)
(funcall continuation))
(rplaca place nil))))))
(defmacro with-recursive-lock-held ((place &optional state) &body forms)
#+(or Xerox Genera ccl Minima)
(declare (ignore state #+ccl place))
#{Genera `(process:with-lock (,place) ,@forms)
Minima `(minima:with-lock (,place) ,@forms)
CCL-2 `(progn ,@forms)
otherwise `(with-simple-recursive-lock (,place ,state) ,@forms)
}
)
(defun make-recursive-lock (&optional (lock-name "a recursive CLIM lock"))
#-(or Genera Minima) (declare (ignore lock-name))
#{CCL-2 nil
Genera (process:make-lock lock-name :recursive T)
Minima (minima:make-lock lock-name :recursive T)
otherwise (cons nil nil)
}
)
;;; Atomic operations
(defmacro without-scheduling (&body forms)
"Evaluate the forms w/o letting any other process run."
#{
allegro `(excl:without-interrupts ,@forms)
lispworks `(sys::without-scheduling ,@forms)
Lucid `(lcl:with-scheduling-inhibited ,@forms)
Xerox `(progn ,@forms)
Cloe-Runtime `(progn ,@forms)
aclpc `(progn ,@forms)
;; should be process:with-no-other-processes if this is used as
;; a global locking mechanism
Genera `(scl:without-interrupts ,@forms)
Minima `(minima:with-no-other-processes ,@forms)
CCL-2 `(ccl:without-interrupts ,@forms) ; slh
}
)
;; Atomically increments a fixnum value
#+Genera
(defmacro atomic-incf (reference &optional (delta 1))
(let ((location '#:location)
(old-value '#:old)
(new-value '#:new))
`(loop with ,location = (scl:locf ,reference)
for ,old-value = (scl:location-contents ,location)
for ,new-value = (sys:%32-bit-plus ,old-value ,delta)
do (when (scl:store-conditional ,location ,old-value ,new-value)
(return ,new-value)))))
#-Genera
(defmacro atomic-incf (reference &optional (delta 1))
(let ((value '#:value))
(if (= delta 1)
`(without-scheduling
(let ((,value ,reference))
(if (eq ,value most-positive-fixnum)
(setf ,reference most-negative-fixnum)
(setf ,reference (the fixnum (1+ (the fixnum ,value)))))))
#+ignore (warn "Implement ~S for the case when delta is not 1" 'atomic-incf)
#-ignore ;; maybe?
(if (< delta 0)
`(without-scheduling
(let ((,value ,reference))
(if (< ,delta (- ,value most-negative-fixnum))
(setf ,reference most-positive-fixnum)
(setf ,reference (the fixnum (+ (the fixnum ,delta) (the fixnum ,value)))))))
`(without-scheduling
(let ((,value ,reference))
(if (> ,delta (- most-positive-fixnum ,value))
(setf ,reference most-negative-fixnum)
(setf ,reference (the fixnum (+ (the fixnum ,delta) (the fixnum ,value))))))))
)))
;; Atomically decrements a fixnum value
#+Genera
(defmacro atomic-decf (reference &optional (delta 1))
(let ((location '#:location)
(old-value '#:old)
(new-value '#:new))
`(loop with ,location = (scl:locf ,reference)
for ,old-value = (scl:location-contents ,location)
for ,new-value = (sys:%32-bit-difference ,old-value ,delta)
do (when (scl:store-conditional ,location ,old-value ,new-value)
(return ,new-value)))))
#-Genera
(defmacro atomic-decf (reference &optional (delta 1))
(let ((value '#:value))
(if (= delta 1)
`(without-scheduling
(let ((,value ,reference))
(if (eq ,value most-negative-fixnum)
(setf ,reference most-positive-fixnum)
(setf ,reference (the fixnum (1- (the fixnum ,value)))))))
(warn "Implement ~S for the case when delta is not 1" 'atomic-decf))))
;;; Processes
(defun make-process (function &key name)
#+(or ccl) (declare (ignore function name))
(when *multiprocessing-p*
#{
lispworks (mp:process-run-function name nil function)
Lucid (lcl:make-process :function function :name name)
allegro (mp:process-run-function name function)
Xerox (il:add.process (funcall function) 'il:name name)
Genera (scl:process-run-function name function)
Minima (minima:make-process name :initial-function function)
otherwise (warn "No implementation of MAKE-PROCESS for this system.")
}))
(eval-when (compile load eval) (proclaim '(inline processp)))
(defun processp (object)
#{
ccl (member object '(:user :event :interrupt))
Lucid (lcl:processp object)
allegro (mp::process-p object)
lispworks (mp::process-p object)
;; In 7.3 and after it is `(process:process-p ,object)
Genera (process:process-p object)
Minima (typep object 'minima-internals::basic-process)
otherwise (progn (warn "No implementation of PROCESSP for this system.")
nil)
}
)
(defun destroy-process (process)
#+(or ccl) (declare (ignore process))
#{
Lucid (lcl:kill-process process)
allegro (mp:process-kill process)
lispworks (mp:process-kill process)
Xerox (il:del.process process)
Genera (scl:process-kill process)
Minima (minima:process-kill process)
CCL-2 nil
otherwise (warn "No implementation of DESTROY-PROCESS for this system.")
}
)
#+CCL-2
(defvar *current-process* :user)
(eval-when (compile load eval) (proclaim '(inline current-process)))
(defun current-process ()
#{
Lucid lcl:*current-process*
allegro mp:*current-process*
lispworks mp:*current-process*
Xerox (il:this.process)
Genera scl:*current-process*
Minima (minima:current-process)
CCL-2 *current-process*
Cloe-Runtime nil
aclpc nil
}
)
(eval-when (compile load eval) (proclaim '(inline all-processes)))
(defun all-processes ()
#{
Lucid lcl:*all-processes*
allegro mp:*all-processes*
lispworks (mp::list-all-processes)
Genera sys:all-processes
CCL-2 (adjoin *current-process* '(:user))
Cloe-Runtime nil
aclpc nil
}
)
(defun show-processes ()
#{
Lucid (lcl::show-processes)
Genera (si:com-show-processes)
otherwise (all-processes)
}
)
(eval-when (compile load eval) (proclaim '(inline process-yield)))
(defun process-yield ()
#{
Lucid (lcl:process-allow-schedule)
allegro (mp:process-allow-schedule)
lispworks (mp::process-allow-scheduling)
Xerox (il:block)
Genera (scl:process-allow-schedule)
Minima (sleep 1/10)
CCL-2 (ccl:event-dispatch)
Cloe-Runtime nil
aclpc nil
}
)
#-mswindows
(defun process-wait (wait-reason predicate)
#+(or Genera Minima) (declare (dynamic-extent predicate))
"Cause the current process to go to sleep until the predicate returns TRUE."
#{
Lucid (lcl:process-wait wait-reason predicate)
allegro (mp:process-wait wait-reason predicate)
lispworks (mp:process-wait wait-reason predicate)
Xerox (let ((il:*who-line-state* wait-reason))
(loop
(il:block)
(when (and (funcall predicate))
(return))))
CCL-2 (ccl::process-wait wait-reason predicate)
Cloe-Runtime nil
aclpc nil
Genera (scl:process-wait wait-reason predicate)
Minima (minima:process-wait wait-reason predicate)
otherwise (warn "No implementation of PROCESS-WAIT for this system.")
}
)
(defun process-wait-with-timeout (wait-reason timeout predicate)
#+(or Genera Minima) (declare (dynamic-extent predicate))
"Cause the current process to go to sleep until the predicate returns TRUE or
timeout seconds have gone by."
(when (null timeout)
;; ensure genera semantics, timeout = NIL means indefinite timeout
(return-from process-wait-with-timeout
(process-wait wait-reason predicate)))
#{
allegro (mp:process-wait-with-timeout wait-reason timeout predicate)
lispworks (mp:process-wait-with-timeout wait-reason timeout predicate)
Lucid (lcl:process-wait-with-timeout wait-reason timeout predicate)
Genera (sys:process-wait-with-timeout wait-reason (* timeout 60.) predicate)
CCL-2 (ccl::process-wait-with-timeout wait-reason timeout predicate)
otherwise (warn "No implementation of PROCESS-WAIT-WITH-TIMEOUT for this system.")
}
)
(defun process-interrupt (process function)
(declare #+CCL-2 (ignore process))
#{
Lucid (lcl:interrupt-process process function)
allegro (mp:process-interrupt process function)
lispworks (mp:process-interrupt process function)
Genera (scl:process-interrupt process function)
CCL-2 (let ((*current-process* :interrupt))
(funcall function))
Minima (minima:process-interrupt process function)
otherwise (warn "No implementation of PROCESS-INTERRUPT for this system.")
}
)
(defun restart-process (process)
#{
Lucid (lcl::restart-process process)
allegro (mp:process-reset process)
lispworks (mp:process-reset process)
Genera (process:process-reset process)
Minima (minima:process-reset process)
otherwise (warn "No implementation of RESTART-PROCESS for this system.")
}
)
(defun enable-process (process)
#{
Lucid (lcl::activate-process process)
allegro (mp:process-enable process)
lispworks (mp:process-enable process)
Genera (process:process-enable process)
Minima (minima:process-enable process)
otherwise (warn "No implementation of ENABLE-PROCESS for this system.")
}
)
(defun disable-process (process)
#{
Lucid (lcl::deactivate-process process)
allegro (mp:process-disable process)
lispworks (mp:process-disable process)
Genera (process:process-disable process)
Minima (minima:process-disable process)
otherwise (warn "No implementation of DISABLE-PROCESS for this system.")
}
)
(defun process-name (process)
#{
Lucid (lcl::process-name process)
allegro (mp:process-name process)
lispworks (mp:process-name process)
Genera (process:process-name process)
Minima (minima:process-name process)
otherwise (warn "No implementation of PROCESS-NAME for this system.")
}
)
(defun process-state (process)
#{
Lucid (lcl::process-state process)
allegro (cond ((mp:process-active-p process) "active")
((mp:process-runnable-p process) "runnable")
(t "deactivated"))
lispworks (cond ((mp:process-active-p process) "active")
((mp:process-runnable-p process) "runnable")
(t "deactivated"))
Genera (process:process-state process)
Minima (minima:process-state process)
otherwise (warn "No implementation of PROCESS-STATE for this system.")
}
)
(defun process-whostate (process)
#{
Lucid (lcl::process-whostate process)
allegro (mp:process-whostate process)
lispworks (mp:process-whostate process)
Genera (process:process-whostate process)
Minima (minima:process-whostate process)
otherwise (warn "No implementation of PROCESS-WHOSTATE for this system.")
}
)