impl-cmucl.lisp - clic - Clic is an command line interactive client for gopher written in Common LISP
 (HTM) git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
       impl-cmucl.lisp (4919B)
       ---
            1 ;;;; -*- indent-tabs-mode: nil -*-
            2 
            3 #|
            4 Copyright 2006, 2007 Greg Pfeil
            5 
            6 Distributed under the MIT license (see LICENSE file)
            7 |#
            8 
            9 (in-package #:bordeaux-threads)
           10 
           11 (deftype thread ()
           12   'mp::process)
           13 
           14 ;;; Thread Creation
           15 
           16 (defun start-multiprocessing ()
           17   (mp::startup-idle-and-top-level-loops))
           18 
           19 (defun %make-thread (function name)
           20   #+#.(cl:if (cl:find-symbol (cl:string '#:process-join) :mp) '(and) '(or))
           21   (mp:make-process function :name name)
           22   #-#.(cl:if (cl:find-symbol (cl:string '#:process-join) :mp) '(and) '(or))
           23   (mp:make-process (lambda ()
           24                      (let ((return-values
           25                              (multiple-value-list (funcall function))))
           26                        (setf (getf (mp:process-property-list mp:*current-process*)
           27                                    'return-values)
           28                              return-values)
           29                        (values-list return-values)))
           30                    :name name))
           31 
           32 (defun current-thread ()
           33   mp:*current-process*)
           34 
           35 (defmethod threadp (object)
           36   (mp:processp object))
           37 
           38 (defun thread-name (thread)
           39   (mp:process-name thread))
           40 
           41 ;;; Resource contention: locks and recursive locks
           42 
           43 (deftype lock () 'mp::error-check-lock)
           44 
           45 (deftype recursive-lock () 'mp::recursive-lock)
           46 
           47 (defun lock-p (object)
           48   (typep object 'mp::error-check-lock))
           49 
           50 (defun recursive-lock-p (object)
           51   (typep object 'mp::recursive-lock))
           52 
           53 (defun make-lock (&optional name)
           54   (mp:make-lock (or name "Anonymous lock")
           55                 :kind :error-check))
           56 
           57 (defun acquire-lock (lock &optional (wait-p t))
           58   (if wait-p
           59       (mp::lock-wait lock "Lock wait")
           60       (mp::lock-wait-with-timeout lock "Lock wait" 0)))
           61 
           62 (defun release-lock (lock)
           63   (setf (mp::lock-process lock) nil))
           64 
           65 (defmacro with-lock-held ((place) &body body)
           66   `(mp:with-lock-held (,place "Lock wait") ,@body))
           67 
           68 (defun make-recursive-lock (&optional name)
           69   (mp:make-lock (or name "Anonymous recursive lock")
           70                 :kind :recursive))
           71 
           72 (defun acquire-recursive-lock (lock &optional (wait-p t))
           73   (acquire-lock lock))
           74 
           75 (defun release-recursive-lock (lock)
           76   (release-lock lock))
           77 
           78 (defmacro with-recursive-lock-held ((place &key timeout) &body body)
           79   `(mp:with-lock-held (,place "Lock Wait" :timeout ,timeout) ,@body))
           80 
           81 ;;; Note that the locks _are_ recursive, but not "balanced", and only
           82 ;;; checked if they are being held by the same process by with-lock-held.
           83 ;;; The default with-lock-held in bordeaux-mp.lisp sort of works, in that
           84 ;;; it will wait for recursive locks by the same process as well.
           85 
           86 ;;; Resource contention: condition variables
           87 
           88 ;;; There's some stuff in x86-vm.lisp that might be worth investigating
           89 ;;; whether to build on. There's also process-wait and friends.
           90 
           91 (defstruct condition-var
           92   "CMUCL doesn't have conditions, so we need to create our own type."
           93   name
           94   lock
           95   active)
           96 
           97 (defun make-condition-variable (&key name)
           98   (make-condition-var :lock (make-lock)
           99                       :name (or name "Anonymous condition variable")))
          100 
          101 (defun condition-wait (condition-variable lock &key timeout)
          102   (signal-error-if-condition-wait-timeout timeout)
          103   (check-type condition-variable condition-var)
          104   (with-lock-held ((condition-var-lock condition-variable))
          105     (setf (condition-var-active condition-variable) nil))
          106   (release-lock lock)
          107   (mp:process-wait "Condition Wait"
          108                    #'(lambda () (condition-var-active condition-variable)))
          109   (acquire-lock lock)
          110   t)
          111 
          112 (define-condition-wait-compiler-macro)
          113 
          114 (defun condition-notify (condition-variable)
          115   (check-type condition-variable condition-var)
          116   (with-lock-held ((condition-var-lock condition-variable))
          117     (setf (condition-var-active condition-variable) t))
          118   (thread-yield))
          119 
          120 (defun thread-yield ()
          121   (mp:process-yield))
          122 
          123 ;;; Timeouts
          124 
          125 (defmacro with-timeout ((timeout) &body body)
          126   (once-only (timeout)
          127     `(mp:with-timeout (,timeout (error 'timeout :length ,timeout))
          128        ,@body)))
          129 
          130 ;;; Introspection/debugging
          131 
          132 (defun all-threads ()
          133   (mp:all-processes))
          134 
          135 (defun interrupt-thread (thread function &rest args)
          136   (flet ((apply-function ()
          137            (if args
          138                (lambda () (apply function args))
          139                function)))
          140     (declare (dynamic-extent #'apply-function))
          141     (mp:process-interrupt thread (apply-function))))
          142 
          143 (defun destroy-thread (thread)
          144   (signal-error-if-current-thread thread)
          145   (mp:destroy-process thread))
          146 
          147 (defun thread-alive-p (thread)
          148   (mp:process-active-p thread))
          149 
          150 (defun join-thread (thread)
          151   #+#.(cl:if (cl:find-symbol (cl:string '#:process-join) :mp) '(and) '(or))
          152   (mp:process-join thread)
          153   #-#.(cl:if (cl:find-symbol (cl:string '#:process-join) :mp) '(and) '(or))
          154   (progn
          155     (mp:process-wait (format nil "Waiting for thread ~A to complete" thread)
          156                      (lambda () (not (mp:process-alive-p thread))))
          157     (let ((return-values
          158             (getf (mp:process-property-list thread) 'return-values)))
          159       (values-list return-values))))
          160 
          161 (mark-supported)