SpinLock.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include "SpinLock.h"
00019 #include "../debug/StackTrace.h"
00020 
00021 namespace oasys {
00022 
00023 bool     SpinLock::warn_on_contention_(true);
00024 #ifndef NDEBUG
00025 atomic_t SpinLock::total_spins_(0);
00026 atomic_t SpinLock::total_yields_(0);
00027 #endif
00028 
00029 int
00030 SpinLock::lock(const char* lock_user)
00031 {
00032     if (is_locked_by_me()) {
00033         lock_count_.value++;
00034         return 0;
00035     }
00036 
00037     atomic_incr(&lock_waiters_);
00038     
00039     int nspins = 0;
00040     (void)nspins;
00041     while (atomic_cmpxchg32(&lock_count_, 0, 1) != 0)
00042     {
00043         Thread::spin_yield();
00044         
00045 #ifndef NDEBUG
00046         atomic_incr(&total_spins_);
00047         if (warn_on_contention_ && ++nspins > 1000000) {
00048             fprintf(stderr,
00049                     "warning: %s is waiting for spin lock held by %s, which has reached spin limit\n",
00050                     lock_user, lock_holder_name_);
00051             StackTrace::print_current_trace(false);
00052             nspins = 0;
00053         }
00054 #endif
00055     }
00056 
00057     atomic_decr(&lock_waiters_);
00058 
00059     ASSERT(lock_count_.value == 1);
00060 
00061     lock_holder_      = Thread::current();
00062     lock_holder_name_ = lock_user;
00063 
00064     return 0;
00065 };
00066 
00067 int
00068 SpinLock::unlock()
00069 {
00070     ASSERT(is_locked_by_me());
00071 
00072     if (lock_count_.value > 1) {
00073         lock_count_.value--;
00074         return 0;
00075     }
00076 
00077     lock_holder_      = 0;
00078     lock_holder_name_ = 0;
00079     lock_count_.value = 0;
00080     
00081     if (lock_waiters_.value != 0) {
00082 #ifndef NDEBUG
00083         atomic_incr(&total_yields_);
00084 #endif
00085         Thread::spin_yield();
00086     }
00087 
00088 
00089     return 0;
00090 };
00091  
00092 int
00093 SpinLock::try_lock(const char* lock_user)
00094 {
00095     if (is_locked_by_me()) {
00096         lock_count_.value++;
00097         return 0;
00098     }
00099 
00100     int got_lock = atomic_cmpxchg32(&lock_count_, 0, 1);
00101     
00102     if (got_lock) {
00103         ASSERT(lock_holder_ == 0);
00104 
00105         lock_holder_      = Thread::current();
00106         lock_holder_name_ = lock_user;
00107         
00108         return 0; // success
00109         
00110     } else {
00111         return 1; // already locked
00112     }
00113 };
00114 
00115 } // namespace oasys

Generated on Thu Jun 7 16:56:52 2007 for DTN Reference Implementation by  doxygen 1.5.1