Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5078 serge 1
/**************************************************************************
2
 *
3
 * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
4
 * All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sub license, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice (including the
15
 * next paragraph) shall be included in all copies or substantial portions
16
 * of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 **************************************************************************/
27
/*
28
 * Authors: Thomas Hellstrom 
29
 */
30
 
31
#include 
32
#include 
33
#include 
34
//#include 
35
#include 
36
#include 
37
#include 
38
#include 
39
 
40
#define TTM_WRITE_LOCK_PENDING    (1 << 0)
41
#define TTM_VT_LOCK_PENDING       (1 << 1)
42
#define TTM_SUSPEND_LOCK_PENDING  (1 << 2)
43
#define TTM_VT_LOCK               (1 << 3)
44
#define TTM_SUSPEND_LOCK          (1 << 4)
45
 
46
void ttm_lock_init(struct ttm_lock *lock)
47
{
48
	spin_lock_init(&lock->lock);
49
	init_waitqueue_head(&lock->queue);
50
	lock->rw = 0;
51
	lock->flags = 0;
52
}
53
EXPORT_SYMBOL(ttm_lock_init);
54
 
55
void ttm_read_unlock(struct ttm_lock *lock)
56
{
57
	spin_lock(&lock->lock);
58
	if (--lock->rw == 0)
59
		wake_up_all(&lock->queue);
60
	spin_unlock(&lock->lock);
61
}
62
EXPORT_SYMBOL(ttm_read_unlock);
63
 
64
static bool __ttm_read_lock(struct ttm_lock *lock)
65
{
66
	bool locked = false;
67
 
68
	spin_lock(&lock->lock);
69
	if (lock->rw >= 0 && lock->flags == 0) {
70
		++lock->rw;
71
		locked = true;
72
	}
73
	spin_unlock(&lock->lock);
74
	return locked;
75
}
76
 
77
int ttm_read_lock(struct ttm_lock *lock, bool interruptible)
78
{
79
	int ret = 0;
80
 
81
	if (interruptible)
82
		ret = wait_event_interruptible(lock->queue,
83
					       __ttm_read_lock(lock));
84
	else
85
		wait_event(lock->queue, __ttm_read_lock(lock));
86
	return ret;
87
}
88
EXPORT_SYMBOL(ttm_read_lock);
89
 
90
static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked)
91
{
92
	bool block = true;
93
 
94
	*locked = false;
95
 
96
	spin_lock(&lock->lock);
97
	if (lock->rw >= 0 && lock->flags == 0) {
98
		++lock->rw;
99
		block = false;
100
		*locked = true;
101
	} else if (lock->flags == 0) {
102
		block = false;
103
	}
104
	spin_unlock(&lock->lock);
105
 
106
	return !block;
107
}
108
 
109
int ttm_read_trylock(struct ttm_lock *lock, bool interruptible)
110
{
111
	int ret = 0;
112
	bool locked;
113
 
114
	if (interruptible)
115
		ret = wait_event_interruptible
116
			(lock->queue, __ttm_read_trylock(lock, &locked));
117
	else
118
		wait_event(lock->queue, __ttm_read_trylock(lock, &locked));
119
 
120
	if (unlikely(ret != 0)) {
121
		BUG_ON(locked);
122
		return ret;
123
	}
124
 
125
	return (locked) ? 0 : -EBUSY;
126
}
127
 
128
void ttm_write_unlock(struct ttm_lock *lock)
129
{
130
	spin_lock(&lock->lock);
131
	lock->rw = 0;
132
	wake_up_all(&lock->queue);
133
	spin_unlock(&lock->lock);
134
}
135
EXPORT_SYMBOL(ttm_write_unlock);
136
 
137
static bool __ttm_write_lock(struct ttm_lock *lock)
138
{
139
	bool locked = false;
140
 
141
	spin_lock(&lock->lock);
142
	if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) {
143
		lock->rw = -1;
144
		lock->flags &= ~TTM_WRITE_LOCK_PENDING;
145
		locked = true;
146
	} else {
147
		lock->flags |= TTM_WRITE_LOCK_PENDING;
148
	}
149
	spin_unlock(&lock->lock);
150
	return locked;
151
}
152
 
153
int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
154
{
155
	int ret = 0;
156
 
157
	if (interruptible) {
158
		ret = wait_event_interruptible(lock->queue,
159
					       __ttm_write_lock(lock));
160
		if (unlikely(ret != 0)) {
161
			spin_lock(&lock->lock);
162
			lock->flags &= ~TTM_WRITE_LOCK_PENDING;
163
			wake_up_all(&lock->queue);
164
			spin_unlock(&lock->lock);
165
		}
166
	} else
167
		wait_event(lock->queue, __ttm_read_lock(lock));
168
 
169
	return ret;
170
}
171
EXPORT_SYMBOL(ttm_write_lock);
172
 
173
static int __ttm_vt_unlock(struct ttm_lock *lock)
174
{
175
	int ret = 0;
176
 
177
	spin_lock(&lock->lock);
178
	if (unlikely(!(lock->flags & TTM_VT_LOCK)))
179
		ret = -EINVAL;
180
	lock->flags &= ~TTM_VT_LOCK;
181
	wake_up_all(&lock->queue);
182
	spin_unlock(&lock->lock);
183
 
184
	return ret;
185
}
186
 
187
static void ttm_vt_lock_remove(struct ttm_base_object **p_base)
188
{
189
	struct ttm_base_object *base = *p_base;
190
	struct ttm_lock *lock = container_of(base, struct ttm_lock, base);
191
	int ret;
192
 
193
	*p_base = NULL;
194
	ret = __ttm_vt_unlock(lock);
195
	BUG_ON(ret != 0);
196
}
197
 
198
static bool __ttm_vt_lock(struct ttm_lock *lock)
199
{
200
	bool locked = false;
201
 
202
	spin_lock(&lock->lock);
203
	if (lock->rw == 0) {
204
		lock->flags &= ~TTM_VT_LOCK_PENDING;
205
		lock->flags |= TTM_VT_LOCK;
206
		locked = true;
207
	} else {
208
		lock->flags |= TTM_VT_LOCK_PENDING;
209
	}
210
	spin_unlock(&lock->lock);
211
	return locked;
212
}
213
 
214
int ttm_vt_lock(struct ttm_lock *lock,
215
		bool interruptible,
216
		struct ttm_object_file *tfile)
217
{
218
	int ret = 0;
219
 
220
	if (interruptible) {
221
		ret = wait_event_interruptible(lock->queue,
222
					       __ttm_vt_lock(lock));
223
		if (unlikely(ret != 0)) {
224
			spin_lock(&lock->lock);
225
			lock->flags &= ~TTM_VT_LOCK_PENDING;
226
			wake_up_all(&lock->queue);
227
			spin_unlock(&lock->lock);
228
			return ret;
229
		}
230
	} else
231
		wait_event(lock->queue, __ttm_vt_lock(lock));
232
 
233
	/*
234
	 * Add a base-object, the destructor of which will
235
	 * make sure the lock is released if the client dies
236
	 * while holding it.
237
	 */
238
 
239
	ret = ttm_base_object_init(tfile, &lock->base, false,
240
				   ttm_lock_type, &ttm_vt_lock_remove, NULL);
241
	if (ret)
242
		(void)__ttm_vt_unlock(lock);
243
	else
244
		lock->vt_holder = tfile;
245
 
246
	return ret;
247
}
248
EXPORT_SYMBOL(ttm_vt_lock);
249
 
250
int ttm_vt_unlock(struct ttm_lock *lock)
251
{
252
	return ttm_ref_object_base_unref(lock->vt_holder,
253
					 lock->base.hash.key, TTM_REF_USAGE);
254
}
255
EXPORT_SYMBOL(ttm_vt_unlock);
256
 
257
void ttm_suspend_unlock(struct ttm_lock *lock)
258
{
259
	spin_lock(&lock->lock);
260
	lock->flags &= ~TTM_SUSPEND_LOCK;
261
	wake_up_all(&lock->queue);
262
	spin_unlock(&lock->lock);
263
}
264
EXPORT_SYMBOL(ttm_suspend_unlock);
265
 
266
static bool __ttm_suspend_lock(struct ttm_lock *lock)
267
{
268
	bool locked = false;
269
 
270
	spin_lock(&lock->lock);
271
	if (lock->rw == 0) {
272
		lock->flags &= ~TTM_SUSPEND_LOCK_PENDING;
273
		lock->flags |= TTM_SUSPEND_LOCK;
274
		locked = true;
275
	} else {
276
		lock->flags |= TTM_SUSPEND_LOCK_PENDING;
277
	}
278
	spin_unlock(&lock->lock);
279
	return locked;
280
}
281
 
282
void ttm_suspend_lock(struct ttm_lock *lock)
283
{
284
	wait_event(lock->queue, __ttm_suspend_lock(lock));
285
}
286
EXPORT_SYMBOL(ttm_suspend_lock);