1/*----------------------------------------------------------------------------
2|   Copyright (C) 1999  Jochen C. Loewer (loewerj@hotmail.com)
3+-----------------------------------------------------------------------------
4|
5|   $Id: domlock.c,v 1.9 2005/06/10 00:21:57 rolf Exp $
6|
7|   The contents of this file are subject to the Mozilla Public License
8|   Version 1.1 (the "License"); you may not use this file except in
9|   compliance with the License. You may obtain a copy of the License at
10|   http://www.mozilla.org/MPL/
11|
12|   Software distributed under the License is distributed on an "AS IS"
13|   basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
14|   License for the specific language governing rights and limitations
15|   under the License.
16|
17|   The Original Code is tDOM.
18|
19|   The Initial Developer of the Original Code is Jochen Loewer
20|   Portions created by Jochen Loewer are Copyright (C) 1998, 1999
21|   Jochen Loewer. All Rights Reserved.
22|
23|   This implements many-readers/single-writer locking of DOM documents.
24|
25|   Contributor(s):
26|       May02  Zoran Vasiljevic  Added this file.
27|
28\---------------------------------------------------------------------------*/
29
30#ifdef TCL_THREADS
31
32#include <dom.h>
33
34
35/*----------------------------------------------------------------------------
36|   Global list of document lock structures. These should be finalized
37|   only on application exit.
38|
39\---------------------------------------------------------------------------*/
40static Tcl_Mutex lockMutex = 0;
41static domlock *domLocks = NULL;
42
43
44/*----------------------------------------------------------------------------
45|   Lock the document according to passed flag
46|
47\---------------------------------------------------------------------------*/
48void
49domLocksLock(domlock *dl, int how)
50{
51
52    Tcl_MutexLock(&dl->mutex);
53
54    switch (how) {
55    case LOCK_READ:
56        while (dl->lrcnt < 0 || dl->numwr > 0) {
57            dl->numrd++;
58            Tcl_ConditionWait(&dl->rcond, &dl->mutex, NULL);
59            dl->numrd--;
60        }
61        dl->lrcnt++;
62        break;
63
64    case LOCK_WRITE:
65        while (dl->lrcnt != 0) {
66            dl->numwr++;
67            Tcl_ConditionWait(&dl->wcond, &dl->mutex, NULL);
68            dl->numwr--;
69        }
70        dl->lrcnt = -1; /* This designates the sole writer */
71        break;
72    }
73
74    Tcl_MutexUnlock(&dl->mutex);
75}
76
77
78/*----------------------------------------------------------------------------
79|   Unlock the previously locked document.
80|
81\---------------------------------------------------------------------------*/
82void
83domLocksUnlock(domlock *dl)
84{
85    Tcl_MutexLock(&dl->mutex);
86
87    if (--dl->lrcnt < 0) {
88        dl->lrcnt = 0;
89    }
90    if (dl->numwr) {
91        Tcl_ConditionNotify(&dl->wcond);
92    } else if (dl->numrd) {
93        Tcl_ConditionNotify(&dl->rcond);
94    }
95
96    Tcl_MutexUnlock (&dl->mutex);
97}
98
99
100/*----------------------------------------------------------------------------
101|   Associate a lock with the document..
102|
103\---------------------------------------------------------------------------*/
104void
105domLocksAttach(domDocument *doc)
106{
107    domlock *dl;
108
109    Tcl_MutexLock(&lockMutex);
110
111    dl = domLocks;
112    if (dl == NULL) {
113        dl = (domlock*)MALLOC(sizeof(domlock));
114        memset(dl, 0, sizeof(domlock));
115    } else {
116        domLocks = dl->next;
117    }
118
119    dl->doc = doc;
120    doc->lock = dl;
121
122    Tcl_MutexUnlock(&lockMutex);
123}
124
125
126/*----------------------------------------------------------------------------
127|   Divorce DOM document from its lock. The lock structure is not
128|   disposed and may be used for locking other documents.
129|
130\---------------------------------------------------------------------------*/
131void
132domLocksDetach(domDocument *doc)
133{
134    domlock *dl = doc->lock;
135
136    Tcl_MutexLock(&lockMutex);
137
138    if (dl->doc != doc) {
139        domPanic("document lock mismatch");
140    }
141
142    dl->next = domLocks;
143    domLocks = dl;
144
145    dl->doc = NULL;
146    doc->lock = NULL;
147
148    Tcl_MutexUnlock(&lockMutex);
149}
150
151
152/*----------------------------------------------------------------------------
153|   Reclaim storage used for lock structures. This should be done only
154|   on application exit.
155|
156\---------------------------------------------------------------------------*/
157void
158domLocksFinalize(ClientData dummy)
159{
160    domlock *tmp, *dl;
161
162    Tcl_MutexLock(&lockMutex);
163
164    dl = domLocks;
165
166    while (dl != NULL) {
167        Tcl_MutexFinalize(&dl->mutex);
168        Tcl_ConditionFinalize(&dl->rcond);
169        Tcl_ConditionFinalize(&dl->wcond);
170        tmp = dl;
171        dl  = dl->next;
172        FREE((char*)tmp);
173    }
174    domLocks = NULL;
175
176    Tcl_MutexUnlock(&lockMutex);
177}
178
179#endif /* TCL_THREADS */
180