1 | ;;+----------------------------------------------------------------------------- |
---|
2 | ;;+ Isidorus |
---|
3 | ;;+ (c) 2008-2010 Marc Kuester, Christoph Ludwig, Lukas Georgieff |
---|
4 | ;;+ |
---|
5 | ;;+ Isidorus is freely distributable under the LLGPL license. |
---|
6 | ;;+ You can find a detailed description in trunk/docs/LLGPL-LICENSE.txt and |
---|
7 | ;;+ trunk/docs/LGPL-LICENSE.txt. |
---|
8 | ;;+----------------------------------------------------------------------------- |
---|
9 | |
---|
10 | (defpackage :isidorus-threading |
---|
11 | (:use :cl :bordeaux-threads) |
---|
12 | (:export :current-readers |
---|
13 | :with-reader-lock |
---|
14 | :with-writer-lock)) |
---|
15 | |
---|
16 | (in-package :isidorus-threading) |
---|
17 | |
---|
18 | (defvar *readerlist-lock* (make-lock "isidorus-threading: current readers lock")) |
---|
19 | (defvar *writer-lock* (make-lock "isidorus-threading: writer lock")) |
---|
20 | (defvar *current-readers* nil) |
---|
21 | |
---|
22 | |
---|
23 | (defun current-readers () |
---|
24 | "Returns a copy of the list which contains all current reader |
---|
25 | threads, *current-readers*" |
---|
26 | (let ((result nil)) |
---|
27 | (with-lock-held (*readerlist-lock*) |
---|
28 | (setf result (copy-list *current-readers*))) |
---|
29 | result)) |
---|
30 | |
---|
31 | |
---|
32 | (defun add-thread-to-reader-list () |
---|
33 | "Adds the current thread to the reader list" |
---|
34 | (with-lock-held (*writer-lock*) |
---|
35 | (with-lock-held (*readerlist-lock*) |
---|
36 | (push (current-thread) *current-readers*)))) |
---|
37 | |
---|
38 | |
---|
39 | (defun remove-thread-from-reader-list () |
---|
40 | "Removes the current threads from the reader list" |
---|
41 | (with-lock-held (*readerlist-lock*) |
---|
42 | (setf *current-readers* |
---|
43 | (delete (current-thread) *current-readers*)))) |
---|
44 | |
---|
45 | |
---|
46 | (defmacro with-reader-lock (&body body) |
---|
47 | "Executes the passed 'body' with the reader lock" |
---|
48 | `(progn |
---|
49 | (add-thread-to-reader-list) |
---|
50 | (let ((result nil)) |
---|
51 | (handler-case |
---|
52 | (setf result ,@body) |
---|
53 | (condition (c) |
---|
54 | (progn |
---|
55 | (remove-thread-from-reader-list) |
---|
56 | (error c)))) |
---|
57 | (remove-thread-from-reader-list) |
---|
58 | result))) |
---|
59 | |
---|
60 | |
---|
61 | (defmacro with-writer-lock (&body body) |
---|
62 | "Executes the passed body when the reader list is empty otherwise |
---|
63 | the do macor loops in 500 ms time interval for a next chance." |
---|
64 | `(with-lock-held (*writer-lock*) |
---|
65 | (do |
---|
66 | ((remaining-readers (current-readers) (current-readers))) |
---|
67 | ((null remaining-readers)) |
---|
68 | (sleep 0.05)) |
---|
69 | ,@body)) |
---|