00001 /******************************************************************************/ 00002 /* */ 00003 /* X r d S y s X S L o c k . c c */ 00004 /* */ 00005 /* (c) 2003 by the Board of Trustees of the Leland Stanford, Jr., University */ 00006 /* All Rights Reserved */ 00007 /* Produced by Andrew Hanushevsky for Stanford University under contract */ 00008 /* DE-AC03-76-SFO0515 with the Department of Energy */ 00009 /******************************************************************************/ 00010 00011 // $Id: XrdSysXSLock.cc 24468 2008-06-22 16:47:03Z ganis $ 00012 00013 const char *XrdSysXSLockCVSID = "$Id: XrdSysXSLock.cc 24468 2008-06-22 16:47:03Z ganis $"; 00014 00015 #include "XrdSys/XrdSysHeaders.hh" 00016 #include "XrdSys/XrdSysXSLock.hh" 00017 00018 /******************************************************************************/ 00019 /* D e s t r u c t o r */ 00020 /******************************************************************************/ 00021 00022 XrdSysXSLock::~XrdSysXSLock() 00023 { 00024 00025 // Prevent usage while destroying object but make sure no one else is using it 00026 // 00027 LockContext.Lock(); 00028 if (cur_count || shr_wait || exc_wait) 00029 {LockContext.UnLock(); 00030 throw "XSLock_delete: Lock object is still active."; 00031 } 00032 LockContext.UnLock(); 00033 } 00034 00035 /******************************************************************************/ 00036 /* L o c k */ 00037 /******************************************************************************/ 00038 00039 void XrdSysXSLock::Lock(const XrdSysXS_Type usage) 00040 { int FirstTime = 1; 00041 00042 // Serialize access to this object 00043 // 00044 LockContext.Lock(); 00045 00046 // This loop continues until we can acquire the resource. We are gauranteed 00047 // to eventually acquire it regardless of the unblocking order. 00048 // 00049 while(cur_count) 00050 { 00051 // If usage is compatible with current usage get the lock right away 00052 // 00053 if (usage == xs_Shared && cur_usage == xs_Shared && !exc_wait) break; 00054 00055 // Indicate that we are waiting 00056 // 00057 if (FirstTime) 00058 {FirstTime = 0; 00059 if (usage == xs_Shared) shr_wait++; 00060 else exc_wait++; 00061 } 00062 00063 // Usage is not compatible. We must wait for current lock mode to end 00064 // 00065 LockContext.UnLock(); 00066 if (usage == xs_Shared) WantShr.Wait(); 00067 else WantExc.Wait(); 00068 LockContext.Lock(); 00069 } 00070 00071 // We obtained the right to use this object 00072 // 00073 cur_usage = usage; 00074 cur_count++; 00075 LockContext.UnLock(); 00076 } 00077 00078 /******************************************************************************/ 00079 /* U n L o c k */ 00080 /******************************************************************************/ 00081 00082 void XrdSysXSLock::UnLock(const XrdSysXS_Type usage) 00083 { 00084 00085 // Serialize access to our data 00086 // 00087 LockContext.Lock(); 00088 00089 // Make sure that the lock is currently being used 00090 // 00091 if (!cur_count) 00092 {LockContext.UnLock(); 00093 cerr << "XSLock: Attempt to unlock inactive lock." <<endl; 00094 throw "XSLock: unlocking inactive lock."; 00095 } 00096 00097 // Verify that usage is correct 00098 // 00099 if (usage && cur_usage != usage) 00100 {LockContext.UnLock(); 00101 cerr << "XSLock: Incorrect unlock usage - " 00102 << (cur_usage == xs_Shared ? "shr" : "exc") << "!=" 00103 << ( usage == xs_Shared ? "shr" : "exc") << endl; 00104 throw "XSLock: invalid unlock usage specified."; 00105 } 00106 00107 // Unlock the current object. If no locks exist then check if we can let another 00108 // thread use this object. The logic is tricky but we are trying to avoid 00109 // starvation in an environment that has no thread ordering. 00110 // 00111 cur_count--; 00112 if (!cur_count) 00113 if (exc_wait && (toggle || !shr_wait)) 00114 {toggle = 0; WantExc.Post(); exc_wait--;} 00115 else {while(shr_wait) {WantShr.Post(); shr_wait--;} 00116 toggle = 1;} 00117 else if (!toggle) {while(shr_wait) {WantShr.Post(); shr_wait--;} 00118 toggle = 1;} 00119 00120 LockContext.UnLock(); 00121 }