1/* 2 * Copyright 2007-2013 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Niels Sascha Reedijk, niels.reedijk@gmail.com 7 * 8 * Corresponds to: 9 * headers/os/support/Locker.h rev 36218 10 * src/kits/support/Locker.cpp rev 32758 11 */ 12 13/*! 14 \file Locker.h 15 \ingroup support 16 \ingroup libbe 17 \brief Provides locking class BLocker. 18*/ 19 20 21/*! 22 \class BLocker 23 \ingroup support 24 \ingroup libbe 25 \brief Semaphore-type class for thread safety. 26 27 The BLocker interface is not merely a wrapper around a semaphore, but it 28 also has two advantages. First of all, it implements a benaphore. 29 A benaphore is in some ways more speed efficient, 30 because before it uses the internal semaphore, it first checks against a 31 variable that is only operated on with atomic operations. Setting a variable 32 is a lot more efficient than acquiring a semaphore, thus this type of locking 33 is much preferred. 34 35 It basically works as follows. Whenever you newly created BLocker object 36 receives a locking request, it atomically sets the benaphore variable to 37 \c 1. Then only additional calls from different threads will utilize the 38 semaphore. You can imagine that in many cases where you protect 39 of data that \em might be accessed by two or more concurrent threads, but 40 the chances of it happening being very small, the benaphore benefits the 41 most from it's speed. 42 43 The other feature of BLocker that improves basic semaphore handling is that 44 it allows for recursive locks. The following piece of code works with a 45 BLocker, but block inevitably with a semaphore. Let's pretend I call 46 \c Water(): 47 48\code 49status_t 50Flower::Grow(int length) 51{ 52 if (fLock->Lock()) { 53 fLength += length; 54 fLock->Unlock(); 55 return B_OK; 56 } else { 57 return B_ERROR; 58 } 59} 60 61status_t 62Flower::Water(int amount) 63{ 64 if (fLock->Lock()) { 65 status_t status = Grow(amount * 2); 66 fLock->Unlock(); 67 return status; 68 } else { 69 return B_ERROR; 70 } 71} 72\endcode 73 74 This code would work because BLocker keeps track of the amount of lock 75 requests from the same thread. A normal semaphore would block in \c Grow() 76 because the semaphore would be acquired already. Please do make sure you 77 pair every Lock() with an Unlock() though, or you'll create a deadlock. 78*/ 79 80 81/*! 82 \fn BLocker::BLocker() 83 \brief Constructor. 84 85 Create a new BLocker with the default name of some BLocker. This 86 BLocker will use the benaphore-style locking. 87 88 \note For debugging purposes, it's extremely convenient to actually give a 89 name to the object. In case of a deadlock, it's easier to track down which 90 BLocker object might have caused the problems. 91 92 \see BLocker(const char* name, bool benaphoreStyle) for all the options. 93*/ 94 95 96/*! 97 \fn BLocker::BLocker(const char* name) 98 \brief Constructor. 99 100 Create a new BLocker with benaphore-style locking. 101 102 \param name A NULL-terminated string that contains the name of the 103 semaphore. Note that the length of the names are limited to 104 \c B_OS_NAME_LENGTH constant, which includes the \c \\0 105 character. 106 107 \see BLocker(const char* name, bool benaphoreStyle) for all the options. 108*/ 109 110 111/*! 112 \fn BLocker::BLocker(bool benaphoreStyle) 113 \brief Constructor. 114 115 Creates a BLocker with the default name of <tt>some BLocker</tt>. 116 117 \note For debugging purposes, it's extremely convenient to actually give a 118 name to the object. In case of a deadlock, it's easier to track down 119 which BLocker object might have caused the problems. 120 121 \param benaphoreStyle If you pass \c true, the locker will be in benaphore 122 style (which is the default option for other constructors). If you 123 pass \c false, the object will completely rely on semaphores for 124 it's functioning. 125 126 \see BLocker(const char* name, bool benaphoreStyle) if you also want 127 to set a name. 128*/ 129 130 131/*! 132 \fn BLocker::BLocker(const char* name, bool benaphoreStyle) 133 \brief Constructor. 134 135 \param name A NULL-terminated string that contains the name of the 136 semaphore. Note that the length of the names are limited to 137 \c B_OS_NAME_LENGTH constant, which includes the \c \\0 138 character. 139 \param benaphoreStyle If you pass \c true, the locker will be in benaphore 140 style (which is the default option for other constructors). If 141 you pass \c false, the object will completely rely on semaphores 142 for its functioning. 143*/ 144 145 146/*! 147 \fn virtual BLocker::~BLocker() 148 \brief Destructor. 149 150 Release the internal semaphore. Because of this, any pending Lock() calls 151 from other threads be cancelled. The return code will be \c false for 152 those calls. 153*/ 154 155 156/*! 157 \fn status_t BLocker::InitCheck() const 158 \brief Check whether the locker has properly initialized 159 160 \retval B_OK The semaphore has been properly initialized 161 \retval (negative) Any other error value that is related to semaphore 162 initialization 163*/ 164 165 166/*! 167 \fn bool BLocker::Lock() 168 \brief Add a lock request and block on it until we get it. 169 170 \retval true Lock acquired successfully. 171 \retval false Failed to acquire the lock. Most probable cause is that the 172 object is deleted. This frees the semaphore and releases the 173 pending Lock() requests. 174 175 \see LockWithTimeout(bigtime_t timeout), Unlock() 176*/ 177 178 179/*! 180 \fn status_t BLocker::LockWithTimeout(bigtime_t timeout) 181 \brief Add a lock request and block until we get it or until it times out. 182 183 \param timeout This is a timeout in microseconds (one millionth of a 184 second) relative to now. 185 186 \see Lock(), Unlock() 187*/ 188 189 190/*! 191 \fn void BLocker::Unlock(void) 192 \brief Release the lock that's currently held. 193*/ 194 195 196/*! 197 \fn thread_id BLocker::LockingThread(void) const 198 \brief Return the \c thread_id of the thread that's currently holding the 199 lock. 200*/ 201 202 203/*! 204 \fn bool BLocker::IsLocked(void) const 205 \brief Check if the calling thread is actually holding the lock. 206 207 \retval true The thread from which this method is called from is currently 208 holding the lock. 209 \retval false The object is unlocked or the lock is held by another thread. 210*/ 211 212 213/*! 214 \fn int32 BLocker::CountLocks(void) const 215 \brief Return the number of recursive locks that are currently held. 216*/ 217 218 219/*! 220 \fn nt32 BLocker::CountLockRequests(void) const 221 \brief Return the number of threads with a pending lock request. 222*/ 223 224 225/*! 226 \fn sem_id BLocker::Sem(void) const 227 \brief Return the sem_id of the semaphore this object holds. 228 229 \warning Like any other internal objects that the Haiku API might expose, 230 this semaphore id should in general be left alone. You should not use any 231 of the public low-level semaphore functions on this semaphore, because it 232 will harm the internal consistency of the object. 233*/ 234