]> matita.cs.unibo.it Git - helm.git/blob - helm/hbugs/common/threadSafe.ml
9fa10d8d0d82635a1f203a5638006ce2599924c3
[helm.git] / helm / hbugs / common / threadSafe.ml
1 (*
2  *  Copyright (C) 2003, HELM Team.
3  *
4  *  This file is part of HELM, an Hypertextual, Electronic
5  *  Library of Mathematics, developed at the Computer Science
6  *  Department, University of Bologna, Italy.
7  *
8  *  HELM is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU General Public License
10  *  as published by the Free Software Foundation; either version 2
11  *  of the License, or (at your option) any later version.
12  *
13  *  HELM is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with HELM; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21  *  MA  02111-1307, USA.
22  *
23  *  For details, see the HELM World-Wide-Web page,
24  *  http://cs.unibo.it/helm/.
25  *)
26
27 let debug_print = let debug = false in fun s -> if debug then prerr_endline s;;
28
29 class threadSafe =
30   object (self)
31
32     val mutex = Mutex.create ()
33
34       (** condition variable: 'no readers is currently reading' *)
35     val noReaders = Condition.create ()
36
37       (** readers count *)
38     val mutable readersCount = 0
39
40     method private incrReadersCount = (* internal, not exported *)
41       self#doCritical (lazy (
42         readersCount <- readersCount + 1
43       ))
44
45     method private decrReadersCount = (* internal, not exported *)
46       self#doCritical (lazy (
47         if readersCount > 0 then readersCount <- readersCount - 1;
48       ))
49
50     method private signalNoReaders =  (* internal, not exported *)
51       self#doCritical (lazy (
52         if readersCount = 0 then Condition.signal noReaders
53       ))
54
55     method private doCritical: 'a. 'a lazy_t -> 'a =
56       fun action ->
57         debug_print "<doCritical>";
58         (try
59           Mutex.lock mutex;
60           let res = Lazy.force action in
61           Mutex.unlock mutex;
62           debug_print "</doCritical>";
63           res
64         with e ->
65           Mutex.unlock mutex;
66           raise e);
67
68     method private doReader: 'a. 'a lazy_t -> 'a =
69       fun action ->
70         debug_print "<doReader>";
71         let cleanup () =
72           self#decrReadersCount;
73           self#signalNoReaders
74         in
75         self#incrReadersCount;
76         let res = (try Lazy.force action with e -> (cleanup (); raise e)) in
77         cleanup ();
78         debug_print "</doReader>";
79         res
80
81       (* TODO may starve!!!! is what we want or not? *)
82     method private doWriter: 'a. 'a lazy_t -> 'a =
83       fun action ->
84         debug_print "<doWriter>";
85         self#doCritical (lazy (
86           while readersCount > 0 do
87             Condition.wait noReaders mutex
88           done;
89           let res = Lazy.force action in
90           debug_print "</doWriter>";
91           res
92         ))
93
94   end