*** empty log message ***
[csql.git] / src / storage / Mutex.cxx
blob64ce3d43bf57624a275e0ef742ab22840f37ce62
1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 ***************************************************************************/
16 #include <os.h>
17 #include <Mutex.h>
18 #include <Debug.h>
19 #include <NanoTimer.h>
20 #include <Config.h>
21 #include <Process.h>
22 Mutex::Mutex()
24 #if defined(sparc) || defined(i686) || defined (x86_64)
25 lock =0;
26 #else
27 pthread_mutexattr_t attr;
28 pthread_mutexattr_init(&attr);
29 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
30 pthread_mutex_init(&mutex_, &attr);
31 #endif
34 int Mutex::init()
36 #if defined(sparc) || defined(i686) || defined (x86_64)
37 lock = 0;
38 #else
39 pthread_mutexattr_t attr;
40 pthread_mutexattr_init(&attr);
41 int ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
42 printf("pthread_mutexattr_setpshared Returned %d\n", ret);
43 pthread_mutex_init(&mutex_, &attr);
44 pthread_mutexattr_destroy(&attr);
45 #endif
46 return 0;
48 int Mutex::init(char *mname)
50 init();
51 if (strlen(mname) > 19 ) return 0;
52 strcpy(name, mname);
53 return 0;
57 #if defined(sparc) || defined(i686) || defined (x86_64)
58 int TSL(Lock *lock)
61 if (lock == 0) {
62 __asm("mov $1, %eax");
63 __asm("mov 20(%ebp), %edx");
64 __asm("xchg %eax, (%edx)");
65 __asm("test %eax %eax");
66 __asm("jnz .L1000");
67 return 0;
68 } else
70 __asm(".L1000:");
71 return 1;
74 /*Was Working in linux
75 char oldval;
76 __asm__ __volatile__(
77 "xchgb %b0,%1"
78 :"=q" (oldval), "=m" (lock)
79 :"0" (0) : "memory");
81 return oldval > 0;
83 #if defined(LINUX) || defined (FreeBSD)
84 int* lw;
85 int res;
86 lw = (int*)lock;
87 if (*lock == 1) return 1;
88 /* This assembly compiles only with -O2 option, and not with -g option. Version1
89 __asm__ __volatile__(
90 "movl $1, %%eax; xchgl (%%ecx), %%eax"
91 : "=eax" (res), "=m" (*lw)
92 : "ecx" (lw));
95 /* This assembly takes lot of time for test/performance/DMLTest. Version2
96 __asm__ __volatile__(
97 "movl %1, %0; xchgl %0, %2"
98 : "=r" (res), "=r" (lock)
99 : "r" (lock));
103 // This assembly is Version3. Working fine for now
104 __asm__ __volatile__(
105 "xchgl %0, %1 \n\t"
106 : "=r"(res), "=m"(*lock)
107 : "0"(1), "m"(*lock)
108 : "memory");
110 //fprintf(stderr,"after asm %d ret %d\n", *lock, res);
112 return(res);
114 #elif defined (SOLARIS)
115 Lock res;
116 res = atomic_cas_32((unsigned*)lock, 0, 1);
117 return (res);
118 #elif defined (WINNT)
119 printf("WINDOWS TSL not yet implemented\n");
120 return 0;
121 #endif
123 #endif
124 int Mutex::tryShareLock(int tryTimes, int waitmsecs,bool share, bool upgrade)
126 int ret=0;
127 int oldValue = (int)lock;
128 if (oldValue >= 0 && share){
129 ret = CAS((int*)&lock, oldValue, oldValue+1);
130 }else if ((oldValue == 1 && upgrade ) || ( !share && oldValue == 0) ){
131 ret = CAS((int*)&lock, oldValue, -1);
132 }else { ret = 1;}
133 if (0 == ret) return 0;
134 int tries = 1;
135 struct timeval timeout;
136 timeout.tv_sec = 0;
137 timeout.tv_usec = waitmsecs;
138 if (tryTimes == 0 && waitmsecs == 0)
140 timeout.tv_sec = Conf::config.getMutexSecs();
141 timeout.tv_usec = Conf::config.getMutexUSecs();
142 tryTimes = Conf::config.getMutexRetries();
144 int cnt=0;
145 while (tries < tryTimes)
147 #if defined(sparc) || defined(i686) || defined (x86_64)
148 if (Conf::config.getNoOfProcessors() >1) {
149 cnt=0;
150 while(true) {
151 oldValue = (int)lock;
152 if (oldValue >= 0 && share) {
153 ret = CAS((int*)&lock, oldValue, oldValue+1);
154 }else if ((oldValue == 1 && upgrade ) || (!share && oldValue == 0) ) {
155 ret = CAS((int*)&lock, oldValue, -1);
156 }else { ret = 1; }
158 if(0 == ret ) return 0;
159 cnt++;
160 if (cnt == tryTimes * 100) break;
162 }else {
163 oldValue = (int)lock;
164 if (oldValue >= 0 && share) {
165 ret = CAS((int*)&lock, oldValue, oldValue+1);
166 }else if ((oldValue == 1 && upgrade ) || (!share && oldValue == 0) ){
167 ret = CAS((int*)&lock, oldValue, -1);
168 } else { ret =1;}
169 if(ret==0) return 0;
171 #else
172 ret = pthread_mutex_trylock(&mutex_);
173 if (EBUSY != ret) return 0;
175 #endif
176 os::select(0, 0, 0, 0, &timeout);
177 tries++;
179 //printError(ErrLockTimeOut, "Unable to get the mutex %s, tried %d times", name,tries);
180 return 1;
183 int Mutex::tryLock(int tryTimes, int waitmsecs)
185 if (TSL(&lock) == 0)
187 return 0;
189 int tries = 1;
190 int ret = 0;
191 struct timeval timeout;
192 timeout.tv_sec = 0;
193 timeout.tv_usec = waitmsecs;
194 if (tryTimes == 0 && waitmsecs == 0)
196 timeout.tv_sec = Conf::config.getMutexSecs();
197 timeout.tv_usec = Conf::config.getMutexUSecs();
198 tryTimes = Conf::config.getMutexRetries();
200 int cnt=0;
201 while (tries < tryTimes)
203 #if defined(sparc) || defined(i686) || defined (x86_64)
204 if (Conf::config.getNoOfProcessors() >1) {
205 cnt=0;
206 while(true) {
207 if (TSL(&lock) == 0)
209 return 0;
211 cnt++;
212 if (cnt == tryTimes * 100) break;
214 }else {
215 if (TSL(&lock) == 0) return 0;
217 #else
218 ret = pthread_mutex_trylock(&mutex_);
219 if (EBUSY != ret) return 0;
221 #endif
222 os::select(0, 0, 0, 0, &timeout);
223 tries++;
225 //printError(ErrLockTimeOut, "Unable to get the mutex %s, val:%d tried %d times", name, lock, tries);
226 return 1;
229 int Mutex::getLock(int procSlot, bool procAccount)
231 int ret=0;
232 #if defined(sparc) || defined(i686) || defined (x86_64)
233 ret = tryLock();
234 //add it to the has_ of the ThreadInfo
235 if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot);
237 return ret;
238 #else
239 ret = pthread_mutex_lock(&mutex_);
240 #endif
241 if (ret == 0) return 0;
242 else
243 return 1;
246 int Mutex::releaseLock(int procSlot, bool procAccount)
248 int ret=0;
249 #if defined(sparc) || defined(i686) || defined (x86_64)
250 /*int *lw = &lock;
251 if (*lw == 0) return 0;
252 __asm__ __volatile__("movl $0, %%eax; xchgl (%%ecx), %%eax" :
253 "=m" (*lw) :
254 "ecx" (lw) :
255 "eax");
257 lock = 0;
258 //TEMP::PRABA:TODO::CHANGE IT TO CAS
259 #else
260 ret = pthread_mutex_unlock(&mutex_);
261 #endif
262 if (ret == 0 && procAccount)
264 ProcessManager::removeMutex(this, procSlot);
265 return ret;
267 else
268 return 1;
271 int Mutex::getShareLock(int procSlot, bool procAccount)
273 int ret=0;
274 #if defined(sparc) || defined(i686) || defined (x86_64)
275 ret = tryShareLock(0,0,true,false);
276 //add it to the has_ of the ThreadInfo
277 if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot);
278 return ret;
279 #else
280 ret = pthread_mutex_lock(&mutex_);
281 #endif
282 if (ret == 0) return 0;
283 else
284 return 1;
287 int Mutex::getExclusiveLock(int procSlot, bool procAccount, bool upgrade)
289 int ret=0;
290 #if defined(sparc) || defined(i686) || defined (x86_64)
291 ret = tryShareLock(0,0,false,upgrade);
292 //add it to the has_ of the ThreadInfo
293 if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot);
294 return ret;
295 #else
296 ret = pthread_mutex_lock(&mutex_);
297 #endif
298 if (ret == 0) return 0;
299 else
300 return 1;
303 int Mutex::releaseShareLock(int procSlot, bool procAccount)
305 int ret=0;
306 #if defined(sparc) || defined(i686) || defined (x86_64)
307 int oldValue = (int)lock;
308 if( oldValue > 1)
310 ret = CAS((int*)&lock, oldValue, oldValue-1 );
312 if( oldValue == 1 || oldValue == -1 )
314 ret = CAS((int*)&lock, oldValue, 0 );
316 if( ret != 0)
318 int tries = 1;
319 struct timeval timeout;
320 timeout.tv_sec = Conf::config.getMutexSecs();
321 timeout.tv_usec = Conf::config.getMutexUSecs();
322 int tryTimes = Conf::config.getMutexRetries();
323 while (tries < tryTimes)
325 oldValue = (int)lock;
326 if( oldValue > 1){
327 ret = CAS((int*)&lock, oldValue, (*(int*)&lock)-1 );
328 if(ret == 0) break;
330 if( oldValue == 1 || oldValue == -1 )
332 ret = CAS((int*)&lock, oldValue, 0 );
333 if(ret == 0) break;
335 tries++;
338 #else
339 ret = pthread_mutex_unlock(&mutex_);
340 #endif
341 if (ret == 0 && procAccount )
343 ProcessManager::removeMutex(this, procSlot);
344 return ret;
346 else
347 return 1;
350 int Mutex::destroy()
352 #if defined(sparc) || defined(i686) || defined (x86_64)
353 #else
354 return pthread_mutex_destroy(&mutex_);
355 #endif
356 return 0;
359 int Mutex::recoverMutex()
361 int ret=0;
362 #if defined(sparc) || defined(i686) || defined (x86_64)
363 /*int *lw = &lock;
364 if (*lw == 0) return 0;
365 __asm__ __volatile__("movl $0, %%eax; xchgl (%%ecx), %%eax" :
366 "=m" (*lw) :
367 "ecx" (lw) :
368 "eax");
370 lock = 0;
371 #else
372 ret = pthread_mutex_unlock(&mutex_);
373 #endif
374 return ret;
377 int Mutex::CASGen(void *ptr, InUse oldVal, InUse newVal)
379 #if defined(__sparcv9)
380 CASL((InUse *) ptr, oldVal, newVal);
381 return 0;
382 #else
383 CAS((InUse *) ptr, oldVal, newVal);
384 return 0;
385 #endif
388 int Mutex::CASL(long *ptr, long oldVal, long newVal)
390 #ifdef SOLARIS
391 #if defined(__sparcv9) || defined(x86_64) || defined (__x86_64)
392 unsigned long res = atomic_cas_64((unsigned long*)ptr,
393 (unsigned long) oldVal, (unsigned long) newVal);
394 if (res == oldVal) return 0; else return 1;
395 #else
396 return CAS((int*)ptr, (int)oldVal, (int)newVal);
397 #endif
398 #endif
399 #if defined(LINUX) || defined (FreeBSD)
400 #ifdef x86_64
401 long result;
402 __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
403 : "=a" (result), "=m" (*ptr)
404 : "r" (newVal), "m" (*ptr), "0" (oldVal));
405 if (result == oldVal) return 0;
407 struct timeval timeout;
408 timeout.tv_sec=0;
409 timeout.tv_usec=1000;
410 os::select(0,0,0,0, &timeout);
411 __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
412 : "=a" (result), "=m" (*ptr)
413 : "r" (newVal), "m" (*ptr), "0" (oldVal));
415 //if (result) return 0; else {printf("DEBUG::CAS Fails %d-\n", result); return 1; }
416 if (result == oldVal) return 0; else return 1;
417 #else
418 return CAS((int*)ptr, (int)oldVal, (int)newVal);
419 #endif
420 #endif
421 #ifdef WINNT
422 //TODO:: 64 bit support not done.simply routed to CAS
423 //printf("WINDOWS CASL routed to CAS\n");
424 return CAS((int*)ptr, (int)oldVal, (int)newVal);
425 #endif
427 int Mutex::CAS(int *ptr, int oldVal, int newVal)
429 #if defined(LINUX) || defined (FreeBSD)
430 unsigned char ret;
431 __asm__ __volatile__ (
432 " lock\n"
433 " cmpxchgl %2,%1\n"
434 " sete %0\n"
435 : "=q" (ret), "=m" (*ptr)
436 : "r" (newVal), "m" (*ptr), "a" (oldVal)
437 : "memory");
439 //above assembly returns 0 in case of failure
440 if (ret) return 0;
442 struct timeval timeout;
443 timeout.tv_sec=0;
444 timeout.tv_usec=1000;
445 os::select(0,0,0,0, &timeout);
446 __asm__ __volatile__ (
447 " lock\n"
448 " cmpxchgl %2,%1\n"
449 " sete %0\n"
450 : "=q" (ret), "=m" (*ptr)
451 : "r" (newVal), "m" (*ptr), "a" (oldVal)
452 : "memory");
453 //if (ret) return 0; else {printf("DEBUG::CAS Fails %d-\n", ret); return 1; }
454 if (ret) return 0; else return 1;
455 #elif defined SOLARIS //for solaris
456 unsigned int ret;
457 ret = atomic_cas_32((unsigned int*)ptr, (unsigned int) oldVal,
458 (unsigned int) newVal);
459 if (ret == oldVal) return 0; else return 1;
460 #elif defined WINNT
461 printf("WINDOWS Mutex::CAS not implemented\n");
462 return 0;
463 #endif