1/* Utility - some helper classes 2 * 3 * Copyright 2001-2006, Axel D��rfler, axeld@pinc-software.de 4 * This file may be used under the terms of the MIT License. 5 */ 6#ifndef UTILITY_H 7#define UTILITY_H 8 9 10#include "bfs_endian.h" 11 12 13// Simple array, used for the duplicate handling in the B+Tree, 14// and for the log entries. 15 16struct sorted_array { 17 public: 18 off_t count; 19 20#if __MWERKS__ 21 off_t values[1]; 22#else 23 off_t values[0]; 24#endif 25 26 off_t CountItems() const { return BFS_ENDIAN_TO_HOST_INT64(count); } 27 off_t ValueAt(int32 index) const { return BFS_ENDIAN_TO_HOST_INT64(values[index]); } 28 inline int32 Find(off_t value) const; 29 void Insert(off_t value); 30 bool Remove(off_t value); 31 32 private: 33 bool _FindInternal(off_t value, int32 &index) const; 34}; 35 36 37inline int32 38sorted_array::Find(off_t value) const 39{ 40 int32 i; 41 return _FindInternal(value, i) ? i : -1; 42} 43 44 45// The BlockArray reserves a multiple of "blockSize" and 46// maintain array size for new entries. 47// This is used for the in-memory log entries before they 48// are written to disk. 49 50class BlockArray { 51 public: 52 BlockArray(int32 blockSize); 53 ~BlockArray(); 54 55 int32 Find(off_t value); 56 status_t Insert(off_t value); 57 status_t Remove(off_t value); 58 59 void MakeEmpty(); 60 61 int32 CountItems() const { return fArray != NULL ? fArray->CountItems() : 0; } 62 int32 BlocksUsed() const { return fArray != NULL ? ((fArray->CountItems() + 1) * sizeof(off_t) + fBlockSize - 1) / fBlockSize : 0; } 63 sorted_array *Array() const { return fArray; } 64 int32 Size() const { return fSize; } 65 66 private: 67 sorted_array *fArray; 68 int32 fBlockSize; 69 int32 fSize; 70 int32 fMaxBlocks; 71}; 72 73 74// Some atomic operations that are somehow missing in BeOS: 75// 76// _atomic_test_and_set(value, newValue, testAgainst) 77// sets "value" to "newValue", if "value" is equal to "testAgainst" 78// _atomic_set(value, newValue) 79// sets "value" to "newValue" 80 81#if _NO_INLINE_ASM 82 // Note that these atomic versions *don't* work as expected! 83 // They are only used for single processor user space tests 84 // (and don't even work correctly there) 85 inline int32 86 _atomic_test_and_set(volatile int32 *value, int32 newValue, int32 testAgainst) 87 { 88 int32 oldValue = *value; 89 if (oldValue == testAgainst) 90 *value = newValue; 91 92 return oldValue; 93 } 94 95 inline void 96 _atomic_set(volatile int32 *value, int32 newValue) 97 { 98 *value = newValue; 99 } 100#elif __INTEL__ 101 inline int32 102 _atomic_test_and_set(volatile int32 *value, int32 newValue, int32 testAgainst) 103 { 104 int32 oldValue; 105 asm volatile("lock; cmpxchg %%ecx, (%%edx)" 106 : "=a" (oldValue) : "a" (testAgainst), "c" (newValue), "d" (value)); 107 return oldValue; 108 } 109 110 inline void 111 _atomic_set(volatile int32 *value, int32 newValue) 112 { 113 asm volatile("lock; xchg %%eax, (%%edx)" 114 : : "a" (newValue), "d" (value)); 115 } 116#elif __POWERPC__ && __MWERKS__ /* GCC has different assembler syntax */ 117inline asm int32 118 _atomic_set(volatile int32 *value, int32) 119 { 120 loop: 121 dcbf r0, r3; 122 lwarx r0, 0, r3; 123 stwcx. r4, 0, r3; 124 bc 5, 2, loop 125 mr r3,r5; 126 isync; 127 blr; 128 } 129 130inline asm int32 131 _atomic_test_and_set(volatile int32 *value, int32 newValue, int32 testAgainst) 132 { 133 loop: 134 dcbf r0, r3; 135 lwarx r0, 0, r3; 136 cmpw r5, r0; 137 bne no_dice; 138 stwcx. r4, 0, r3; 139 bc 5, 2, loop 140 141 mr r3,r0; 142 isync; 143 blr; 144 145 no_dice: 146 stwcx. r0, 0, r3; 147 mr r3,r0; 148 isync; 149 blr; 150 } 151 152#else 153# error The macros _atomic_set(), and _atomic_test_and_set() are not defined for the target processor 154#endif 155 156 157extern "C" size_t strlcpy(char *dest, char const *source, size_t length); 158 159 160#endif /* UTILITY_H */ 161