2021-08-21 14:58:48 +02:00
|
|
|
;;;
|
|
|
|
;;; Code freely lifted from various places with compatible license
|
|
|
|
;;; terms. Most of this code is copyright Gilbert Baumann
|
|
|
|
;;; <unk6@rz.uni-karlsruhe.de>. The bugs are copyright Walter
|
|
|
|
;;; C. Pelissero <walter@pelissero.de>.
|
|
|
|
;;;
|
|
|
|
|
|
|
|
;;; This library is free software; you can redistribute it and/or
|
|
|
|
;;; modify it under the terms of the GNU Library General Public
|
|
|
|
;;; License as published by the Free Software Foundation; either
|
|
|
|
;;; version 2 of the License, or (at your option) any later version.
|
|
|
|
;;;
|
|
|
|
;;; This library is distributed in the hope that it will be useful,
|
|
|
|
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
;;; Library General Public License for more details.
|
|
|
|
;;;
|
|
|
|
;;; You should have received a copy of the GNU Library General Public
|
|
|
|
;;; License along with this library; if not, write to the
|
|
|
|
;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
;;; Boston, MA 02111-1307 USA.
|
|
|
|
|
|
|
|
(in-package :sclf)
|
|
|
|
|
|
|
|
(defun make-lock (&optional name)
|
|
|
|
(mp:make-lock name))
|
|
|
|
|
|
|
|
(defun make-recursive-lock (&optional name)
|
|
|
|
(mp:make-lock name :kind :recursive))
|
|
|
|
|
|
|
|
(defmacro with-lock-held ((lock &key whostate (wait t) timeout) &body forms)
|
|
|
|
`(mp:with-lock-held (,lock ,(or whostate "Lock Wait")
|
2022-01-19 14:39:58 +01:00
|
|
|
:wait wait
|
|
|
|
,@(when timeout (list :timeout timeout)))
|
2021-08-21 14:58:48 +02:00
|
|
|
,@forms))
|
|
|
|
|
|
|
|
(defmacro with-recursive-lock-held ((lock &key wait timeout) &body forms)
|
|
|
|
`(mp:with-lock-held (,lock
|
2022-01-19 14:39:58 +01:00
|
|
|
,@(when wait (list :wait wait))
|
|
|
|
,@(when timeout (list :timeout timeout)))
|
2021-08-21 14:58:48 +02:00
|
|
|
,@forms))
|
|
|
|
|
|
|
|
(defstruct condition-variable
|
|
|
|
(lock (make-lock "condition variable"))
|
|
|
|
(value nil)
|
|
|
|
(process-queue nil))
|
|
|
|
|
|
|
|
(defun %release-lock (lock) ; copied from with-lock-held in multiproc.lisp
|
|
|
|
#+i486 (kernel:%instance-set-conditional
|
2022-01-19 14:39:58 +01:00
|
|
|
lock 2 mp:*current-process* nil)
|
2021-08-21 14:58:48 +02:00
|
|
|
#-i486 (when (eq (lock-process lock) mp:*current-process*)
|
2022-01-19 14:39:58 +01:00
|
|
|
(setf (lock-process lock) nil)))
|
2021-08-21 14:58:48 +02:00
|
|
|
|
|
|
|
(defun condition-wait (cv lock &optional timeout)
|
|
|
|
(declare (ignore timeout)) ;For now
|
|
|
|
(loop
|
|
|
|
(let ((cv-lock (condition-variable-lock cv)))
|
|
|
|
(with-lock-held (cv-lock)
|
2022-01-19 14:39:58 +01:00
|
|
|
(when (condition-variable-value cv)
|
|
|
|
(setf (condition-variable-value cv) nil)
|
|
|
|
(return-from condition-wait t))
|
|
|
|
(setf (condition-variable-process-queue cv)
|
|
|
|
(nconc (condition-variable-process-queue cv)
|
|
|
|
(list mp:*current-process*)))
|
|
|
|
(%release-lock lock))
|
2021-08-21 14:58:48 +02:00
|
|
|
(mp:process-add-arrest-reason mp:*current-process* cv)
|
|
|
|
(let ((cv-val nil))
|
2022-01-19 14:39:58 +01:00
|
|
|
(with-lock-held (cv-lock)
|
|
|
|
(setq cv-val (condition-variable-value cv))
|
|
|
|
(when cv-val
|
|
|
|
(setf (condition-variable-value cv) nil)))
|
|
|
|
(when cv-val
|
|
|
|
(mp::lock-wait lock "waiting for condition variable lock")
|
|
|
|
(return-from condition-wait t))))))
|
2021-08-21 14:58:48 +02:00
|
|
|
|
|
|
|
(defun condition-notify (cv)
|
|
|
|
(with-lock-held ((condition-variable-lock cv))
|
|
|
|
(let ((proc (pop (condition-variable-process-queue cv))))
|
|
|
|
;; The waiting process may have released the CV lock but not
|
|
|
|
;; suspended itself yet
|
|
|
|
(when proc
|
2022-01-19 14:39:58 +01:00
|
|
|
(loop
|
|
|
|
for activep = (mp:process-active-p proc)
|
|
|
|
while activep
|
|
|
|
do (mp:process-yield))
|
|
|
|
(setf (condition-variable-value cv) t)
|
|
|
|
(mp:process-revoke-arrest-reason proc cv))))
|
2021-08-21 14:58:48 +02:00
|
|
|
;; Give the other process a chance
|
|
|
|
(mp:process-yield))
|
|
|
|
|
|
|
|
(defun process-execute (process function)
|
|
|
|
(mp:process-preset process function)
|
|
|
|
;; For some obscure reason process-preset doesn't make the process
|
|
|
|
;; runnable. I'm sure it's me who didn't understand how
|
|
|
|
;; multiprocessing works under CMUCL, despite the vast documentation
|
|
|
|
;; available.
|
|
|
|
(mp:enable-process process)
|
|
|
|
(mp:process-add-run-reason process :enable))
|
|
|
|
|
|
|
|
(defun destroy-process (process)
|
|
|
|
;; silnetly ignore a process that is trying to destroy itself
|
|
|
|
(unless (eq (mp:current-process)
|
2022-01-19 14:39:58 +01:00
|
|
|
process)
|
2021-08-21 14:58:48 +02:00
|
|
|
(mp:destroy-process process)))
|
|
|
|
|
|
|
|
(defun restart-process (process)
|
|
|
|
(mp:restart-process process)
|
|
|
|
(mp:enable-process process)
|
|
|
|
(mp:process-add-run-reason process :enable))
|
|
|
|
|
|
|
|
(defun process-alive-p (process)
|
|
|
|
(mp:process-alive-p process))
|
|
|
|
|
|
|
|
(defun process-join (process)
|
|
|
|
(error "PROCESS-JOIN not support under CMUCL."))
|