• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.0/libatalk/tdb/
1/*
2   Unix SMB/CIFS implementation.
3   Samba database functions
4   Copyright (C) Anton Blanchard                   2001
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20#define STANDALONE 1
21
22#if HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#if STANDALONE
27#include <stdlib.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <string.h>
31#include <fcntl.h>
32#include <errno.h>
33#include <sys/stat.h>
34#include <time.h>
35#include <signal.h>
36#include "spinlock.h"
37
38#define DEBUG
39#else
40#include "includes.h"
41#endif
42
43#ifdef USE_SPINLOCKS
44
45/*
46 * ARCH SPECIFIC
47 */
48
49#if defined(SPARC_SPINLOCKS)
50
51static inline int __spin_trylock(spinlock_t *lock)
52{
53	unsigned int result;
54
55	asm volatile("ldstub    [%1], %0"
56		: "=r" (result)
57		: "r" (lock)
58		: "memory");
59
60	return (result == 0) ? 0 : EBUSY;
61}
62
63static inline void __spin_unlock(spinlock_t *lock)
64{
65	asm volatile("":::"memory");
66	*lock = 0;
67}
68
69static inline void __spin_lock_init(spinlock_t *lock)
70{
71	*lock = 0;
72}
73
74static inline int __spin_is_locked(spinlock_t *lock)
75{
76	return (*lock != 0);
77}
78
79#elif defined(POWERPC_SPINLOCKS)
80
81static inline int __spin_trylock(spinlock_t *lock)
82{
83	unsigned int result;
84
85	__asm__ __volatile__(
86"1:	lwarx		%0,0,%1\n\
87	cmpwi		0,%0,0\n\
88	li		%0,0\n\
89	bne-		2f\n\
90	li		%0,1\n\
91	stwcx.		%0,0,%1\n\
92	bne-		1b\n\
93	isync\n\
942:"	: "=&r"(result)
95	: "r"(lock)
96	: "cr0", "memory");
97
98	return (result == 1) ? 0 : EBUSY;
99}
100
101static inline void __spin_unlock(spinlock_t *lock)
102{
103	asm volatile("eieio":::"memory");
104	*lock = 0;
105}
106
107static inline void __spin_lock_init(spinlock_t *lock)
108{
109	*lock = 0;
110}
111
112static inline int __spin_is_locked(spinlock_t *lock)
113{
114	return (*lock != 0);
115}
116
117#elif defined(INTEL_SPINLOCKS)
118
119static inline int __spin_trylock(spinlock_t *lock)
120{
121	int oldval;
122
123	asm volatile("xchgl %0,%1"
124		: "=r" (oldval), "=m" (*lock)
125		: "0" (0)
126		: "memory");
127
128	return oldval > 0 ? 0 : EBUSY;
129}
130
131static inline void __spin_unlock(spinlock_t *lock)
132{
133	asm volatile("":::"memory");
134	*lock = 1;
135}
136
137static inline void __spin_lock_init(spinlock_t *lock)
138{
139	*lock = 1;
140}
141
142static inline int __spin_is_locked(spinlock_t *lock)
143{
144	return (*lock != 1);
145}
146
147#elif defined(MIPS_SPINLOCKS)
148
149static inline unsigned int load_linked(unsigned long addr)
150{
151	unsigned int res;
152
153	__asm__ __volatile__("ll\t%0,(%1)"
154		: "=r" (res)
155		: "r" (addr));
156
157	return res;
158}
159
160static inline unsigned int store_conditional(unsigned long addr, unsigned int value)
161{
162	unsigned int res;
163
164	__asm__ __volatile__("sc\t%0,(%2)"
165		: "=r" (res)
166		: "0" (value), "r" (addr));
167	return res;
168}
169
170static inline int __spin_trylock(spinlock_t *lock)
171{
172	unsigned int mw;
173
174	do {
175		mw = load_linked(lock);
176		if (mw)
177			return EBUSY;
178	} while (!store_conditional(lock, 1));
179
180	asm volatile("":::"memory");
181
182	return 0;
183}
184
185static inline void __spin_unlock(spinlock_t *lock)
186{
187	asm volatile("":::"memory");
188	*lock = 0;
189}
190
191static inline void __spin_lock_init(spinlock_t *lock)
192{
193	*lock = 0;
194}
195
196static inline int __spin_is_locked(spinlock_t *lock)
197{
198	return (*lock != 0);
199}
200
201#else
202#error Need to implement spinlock code in spinlock.c
203#endif
204
205/*
206 * OS SPECIFIC
207 */
208
209static void yield_cpu(void)
210{
211	struct timespec tm;
212
213#ifdef USE_SCHED_YIELD
214	sched_yield();
215#else
216	/* Linux will busy loop for delays < 2ms on real time tasks */
217	tm.tv_sec = 0;
218	tm.tv_nsec = 2000000L + 1;
219	nanosleep(&tm, NULL);
220#endif
221}
222
223static int this_is_smp(void)
224{
225	return 0;
226}
227
228/*
229 * GENERIC
230 */
231
232static int smp_machine = 0;
233
234static inline void __spin_lock(spinlock_t *lock)
235{
236	int ntries = 0;
237
238	while(__spin_trylock(lock)) {
239		while(__spin_is_locked(lock)) {
240			if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
241				continue;
242			yield_cpu();
243		}
244	}
245}
246
247static void __read_lock(tdb_rwlock_t *rwlock)
248{
249	int ntries = 0;
250
251	while(1) {
252		__spin_lock(&rwlock->lock);
253
254		if (!(rwlock->count & RWLOCK_BIAS)) {
255			rwlock->count++;
256			__spin_unlock(&rwlock->lock);
257			return;
258		}
259
260		__spin_unlock(&rwlock->lock);
261
262		while(rwlock->count & RWLOCK_BIAS) {
263			if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
264				continue;
265			yield_cpu();
266		}
267	}
268}
269
270static void __write_lock(tdb_rwlock_t *rwlock)
271{
272	int ntries = 0;
273
274	while(1) {
275		__spin_lock(&rwlock->lock);
276
277		if (rwlock->count == 0) {
278			rwlock->count |= RWLOCK_BIAS;
279			__spin_unlock(&rwlock->lock);
280			return;
281		}
282
283		__spin_unlock(&rwlock->lock);
284
285		while(rwlock->count != 0) {
286			if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
287				continue;
288			yield_cpu();
289		}
290	}
291}
292
293static void __write_unlock(tdb_rwlock_t *rwlock)
294{
295	__spin_lock(&rwlock->lock);
296
297#ifdef DEBUG
298	if (!(rwlock->count & RWLOCK_BIAS))
299		fprintf(stderr, "bug: write_unlock\n");
300#endif
301
302	rwlock->count &= ~RWLOCK_BIAS;
303	__spin_unlock(&rwlock->lock);
304}
305
306static void __read_unlock(tdb_rwlock_t *rwlock)
307{
308	__spin_lock(&rwlock->lock);
309
310#ifdef DEBUG
311	if (!rwlock->count)
312		fprintf(stderr, "bug: read_unlock\n");
313
314	if (rwlock->count & RWLOCK_BIAS)
315		fprintf(stderr, "bug: read_unlock\n");
316#endif
317
318	rwlock->count--;
319	__spin_unlock(&rwlock->lock);
320}
321
322/* TDB SPECIFIC */
323
324/* lock a list in the database. list -1 is the alloc list */
325int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type)
326{
327	tdb_rwlock_t *rwlocks;
328
329	if (!tdb->map_ptr) return -1;
330	rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
331
332	switch(rw_type) {
333	case F_RDLCK:
334		__read_lock(&rwlocks[list+1]);
335		break;
336
337	case F_WRLCK:
338		__write_lock(&rwlocks[list+1]);
339		break;
340
341	default:
342		return TDB_ERRCODE(TDB_ERR_LOCK, -1);
343	}
344	return 0;
345}
346
347/* unlock the database. */
348int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type)
349{
350	tdb_rwlock_t *rwlocks;
351
352	if (!tdb->map_ptr) return -1;
353	rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
354
355	switch(rw_type) {
356	case F_RDLCK:
357		__read_unlock(&rwlocks[list+1]);
358		break;
359
360	case F_WRLCK:
361		__write_unlock(&rwlocks[list+1]);
362		break;
363
364	default:
365		return TDB_ERRCODE(TDB_ERR_LOCK, -1);
366	}
367
368	return 0;
369}
370
371int tdb_create_rwlocks(int fd, unsigned int hash_size)
372{
373	unsigned size, i;
374	tdb_rwlock_t *rwlocks;
375
376	size = (hash_size + 1) * sizeof(tdb_rwlock_t);
377	rwlocks = malloc(size);
378	if (!rwlocks)
379		return -1;
380
381	for(i = 0; i < hash_size+1; i++) {
382		__spin_lock_init(&rwlocks[i].lock);
383		rwlocks[i].count = 0;
384	}
385
386	/* Write it out (appending to end) */
387	if (write(fd, rwlocks, size) != size) {
388		free(rwlocks);
389		return -1;
390	}
391	smp_machine = this_is_smp();
392	free(rwlocks);
393	return 0;
394}
395
396int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
397{
398	tdb_rwlock_t *rwlocks;
399	unsigned i;
400
401	if (tdb->header.rwlocks == 0) return 0;
402	if (!tdb->map_ptr) return -1;
403
404	/* We're mmapped here */
405	rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
406	for(i = 0; i < tdb->header.hash_size+1; i++) {
407		__spin_lock_init(&rwlocks[i].lock);
408		rwlocks[i].count = 0;
409	}
410	return 0;
411}
412#else
413int tdb_create_rwlocks(int fd, unsigned int hash_size) { return 0; }
414int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
415int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
416
417/* Non-spinlock version: remove spinlock pointer */
418int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
419{
420	tdb_off off = (tdb_off)((char *)&tdb->header.rwlocks
421				- (char *)&tdb->header);
422
423	tdb->header.rwlocks = 0;
424	if (lseek(tdb->fd, off, SEEK_SET) != off
425	    || write(tdb->fd, (void *)&tdb->header.rwlocks,
426		     sizeof(tdb->header.rwlocks))
427	    != sizeof(tdb->header.rwlocks))
428		return -1;
429	return 0;
430}
431#endif
432