2 Unix SMB/CIFS implementation.
4 trivial database library
6 Copyright (C) Anton Blanchard 2001
8 ** NOTE! The following LGPL license applies to the tdb
9 ** library. This does NOT imply that all of Samba is released
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 2 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
54 #if defined(SPARC_SPINLOCKS)
56 static inline int __spin_trylock(spinlock_t *lock)
60 asm volatile("ldstub [%1], %0"
65 return (result == 0) ? 0 : EBUSY;
68 static inline void __spin_unlock(spinlock_t *lock)
70 asm volatile("":::"memory");
74 static inline void __spin_lock_init(spinlock_t *lock)
79 static inline int __spin_is_locked(spinlock_t *lock)
84 #elif defined(POWERPC_SPINLOCKS)
86 static inline int __spin_trylock(spinlock_t *lock)
103 return (result == 1) ? 0 : EBUSY;
106 static inline void __spin_unlock(spinlock_t *lock)
108 asm volatile("eieio":::"memory");
112 static inline void __spin_lock_init(spinlock_t *lock)
117 static inline int __spin_is_locked(spinlock_t *lock)
122 #elif defined(INTEL_SPINLOCKS)
124 static inline int __spin_trylock(spinlock_t *lock)
128 asm volatile("xchgl %0,%1"
129 : "=r" (oldval), "=m" (*lock)
133 return oldval > 0 ? 0 : EBUSY;
136 static inline void __spin_unlock(spinlock_t *lock)
138 asm volatile("":::"memory");
142 static inline void __spin_lock_init(spinlock_t *lock)
147 static inline int __spin_is_locked(spinlock_t *lock)
152 #elif defined(MIPS_SPINLOCKS)
154 static inline unsigned int load_linked(unsigned long addr)
158 __asm__ __volatile__("ll\t%0,(%1)"
165 static inline unsigned int store_conditional(unsigned long addr, unsigned int value)
169 __asm__ __volatile__("sc\t%0,(%2)"
171 : "0" (value), "r" (addr));
175 static inline int __spin_trylock(spinlock_t *lock)
180 mw = load_linked(lock);
183 } while (!store_conditional(lock, 1));
185 asm volatile("":::"memory");
190 static inline void __spin_unlock(spinlock_t *lock)
192 asm volatile("":::"memory");
196 static inline void __spin_lock_init(spinlock_t *lock)
201 static inline int __spin_is_locked(spinlock_t *lock)
207 #error Need to implement spinlock code in spinlock.c
214 static void yield_cpu(void)
218 #ifdef USE_SCHED_YIELD
221 /* Linux will busy loop for delays < 2ms on real time tasks */
223 tm.tv_nsec = 2000000L + 1;
224 nanosleep(&tm, NULL);
228 static int this_is_smp(void)
237 static int smp_machine = 0;
239 static inline void __spin_lock(spinlock_t *lock)
243 while(__spin_trylock(lock)) {
244 while(__spin_is_locked(lock)) {
245 if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
252 static void __read_lock(tdb_rwlock_t *rwlock)
257 __spin_lock(&rwlock->lock);
259 if (!(rwlock->count & RWLOCK_BIAS)) {
261 __spin_unlock(&rwlock->lock);
265 __spin_unlock(&rwlock->lock);
267 while(rwlock->count & RWLOCK_BIAS) {
268 if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
275 static void __write_lock(tdb_rwlock_t *rwlock)
280 __spin_lock(&rwlock->lock);
282 if (rwlock->count == 0) {
283 rwlock->count |= RWLOCK_BIAS;
284 __spin_unlock(&rwlock->lock);
288 __spin_unlock(&rwlock->lock);
290 while(rwlock->count != 0) {
291 if (smp_machine && ntries++ < MAX_BUSY_LOOPS)
298 static void __write_unlock(tdb_rwlock_t *rwlock)
300 __spin_lock(&rwlock->lock);
303 if (!(rwlock->count & RWLOCK_BIAS))
304 fprintf(stderr, "bug: write_unlock\n");
307 rwlock->count &= ~RWLOCK_BIAS;
308 __spin_unlock(&rwlock->lock);
311 static void __read_unlock(tdb_rwlock_t *rwlock)
313 __spin_lock(&rwlock->lock);
317 fprintf(stderr, "bug: read_unlock\n");
319 if (rwlock->count & RWLOCK_BIAS)
320 fprintf(stderr, "bug: read_unlock\n");
324 __spin_unlock(&rwlock->lock);
329 /* lock a list in the database. list -1 is the alloc list */
330 int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type)
332 tdb_rwlock_t *rwlocks;
334 if (!tdb->map_ptr) return -1;
335 rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
339 __read_lock(&rwlocks[list+1]);
343 __write_lock(&rwlocks[list+1]);
347 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
352 /* unlock the database. */
353 int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type)
355 tdb_rwlock_t *rwlocks;
357 if (!tdb->map_ptr) return -1;
358 rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
362 __read_unlock(&rwlocks[list+1]);
366 __write_unlock(&rwlocks[list+1]);
370 return TDB_ERRCODE(TDB_ERR_LOCK, -1);
376 int tdb_create_rwlocks(int fd, unsigned int hash_size)
379 tdb_rwlock_t *rwlocks;
381 size = TDB_SPINLOCK_SIZE(hash_size);
382 rwlocks = malloc(size);
386 for(i = 0; i < hash_size+1; i++) {
387 __spin_lock_init(&rwlocks[i].lock);
388 rwlocks[i].count = 0;
391 /* Write it out (appending to end) */
392 if (write(fd, rwlocks, size) != size) {
396 smp_machine = this_is_smp();
401 int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
403 tdb_rwlock_t *rwlocks;
406 if (tdb->header.rwlocks == 0) return 0;
407 if (!tdb->map_ptr) return -1;
409 /* We're mmapped here */
410 rwlocks = (tdb_rwlock_t *)((char *)tdb->map_ptr + tdb->header.rwlocks);
411 for(i = 0; i < tdb->header.hash_size+1; i++) {
412 __spin_lock_init(&rwlocks[i].lock);
413 rwlocks[i].count = 0;
418 int tdb_create_rwlocks(int fd, unsigned int hash_size) { return 0; }
419 int tdb_spinlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
420 int tdb_spinunlock(TDB_CONTEXT *tdb, int list, int rw_type) { return -1; }
422 /* Non-spinlock version: remove spinlock pointer */
423 int tdb_clear_spinlocks(TDB_CONTEXT *tdb)
425 tdb_off off = (tdb_off)((char *)&tdb->header.rwlocks
426 - (char *)&tdb->header);
428 tdb->header.rwlocks = 0;
429 if (lseek(tdb->fd, off, SEEK_SET) != off
430 || write(tdb->fd, (void *)&tdb->header.rwlocks,
431 sizeof(tdb->header.rwlocks))
432 != sizeof(tdb->header.rwlocks))