1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
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. *
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. *
15 ***************************************************************************/
19 #include <NanoTimer.h>
24 #if defined(sparc) || defined(i686) || defined (x86_64)
27 pthread_mutexattr_t attr
;
28 pthread_mutexattr_init(&attr
);
29 pthread_mutexattr_setpshared(&attr
, PTHREAD_PROCESS_SHARED
);
30 pthread_mutex_init(&mutex_
, &attr
);
36 #if defined(sparc) || defined(i686) || defined (x86_64)
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
);
49 int Mutex::init(char *mname
)
52 if (strlen(mname
) > 19 ) {
53 printError(ErrNote
, "Mutex name cannot exceeed 20 characters\n");
61 #if defined(sparc) || defined(i686) || defined (x86_64)
62 int TSL(volatile Lock
*lock
)
66 __asm("mov $1, %eax");
67 __asm("mov 20(%ebp), %edx");
68 __asm("xchg %eax, (%edx)");
69 __asm("test %eax %eax");
78 /*Was Working in linux
82 :"=q" (oldval), "=m" (lock)
87 #if defined(LINUX) || defined (FreeBSD)
91 if (*lock
== 1) return 1;
92 /* This assembly compiles only with -O2 option, and not with -g option. Version1
94 "movl $1, %%eax; xchgl (%%ecx), %%eax"
95 : "=eax" (res), "=m" (*lw)
99 /* This assembly takes lot of time for test/performance/DMLTest. Version2
100 __asm__ __volatile__(
101 "movl %1, %0; xchgl %0, %2"
102 : "=r" (res), "=r" (lock)
107 // This assembly is Version3. Working fine for now
108 __asm__
__volatile__(
110 : "=r"(res
), "=m"(*lock
)
114 //fprintf(stderr,"after asm %d ret %d\n", *lock, res);
118 #elif defined (SOLARIS)
120 res
= atomic_cas_32((unsigned*)lock
, 0, 1);
122 #elif defined (WINNT)
123 printf("WINDOWS TSL not yet implemented\n");
128 int Mutex::tryShareLock(int tryTimes
, int waitmsecs
,bool share
, bool upgrade
)
131 int oldValue
= (int)lock
;
132 if (oldValue
>= 0 && share
){
133 ret
= CAS((int*)&lock
, oldValue
, oldValue
+1);
134 }else if ((oldValue
== 1 && upgrade
) || ( !share
&& oldValue
== 0) ){
135 ret
= CAS((int*)&lock
, oldValue
, -1);
138 printDebug(DM_Mutex
, "tryShareLock:%x %s acquired lock:%d", this, name
,lock
);
142 struct timeval timeout
;
144 timeout
.tv_usec
= waitmsecs
;
145 if (tryTimes
== 0 && waitmsecs
== 0)
147 timeout
.tv_sec
= Conf::config
.getMutexSecs();
148 timeout
.tv_usec
= Conf::config
.getMutexUSecs();
149 tryTimes
= Conf::config
.getMutexRetries();
152 while (tries
< tryTimes
)
154 #if defined(sparc) || defined(i686) || defined (x86_64)
155 //if (Conf::config.getNoOfProcessors() >1) {
158 oldValue
= (int)lock
;
159 if (oldValue
>= 0 && share
) {
160 ret
= CAS((int*)&lock
, oldValue
, oldValue
+1);
161 }else if ((oldValue
== 1 && upgrade
) || (!share
&& oldValue
== 0) ) {
162 ret
= CAS((int*)&lock
, oldValue
, -1);
166 printDebug(DM_Mutex
, "tryShareLock:%x %s acquired times:%d lock:%d", this, name
, cnt
, lock
);
170 if (cnt
== tryTimes
* 100) break;
173 oldValue = (int)lock;
174 if (oldValue >= 0 && share) {
175 ret = CAS((int*)&lock, oldValue, oldValue+1);
176 }else if ((oldValue == 1 && upgrade ) || (!share && oldValue == 0) ){
177 ret = CAS((int*)&lock, oldValue, -1);
182 ret
= pthread_mutex_trylock(&mutex_
);
183 if (EBUSY
!= ret
) return 0;
186 os::select(0, 0, 0, 0, &timeout
);
189 printDebug(DM_Mutex
, "Unable to get the mutex %x %s, tried %d times", this, name
,tries
);
193 int Mutex::tryLock(int tryTimes
, int waitmsecs
)
197 printDebug(DM_Mutex
, "tryLock:%x %s acquired lock:%d", this, name
, lock
);
202 struct timeval timeout
;
204 timeout
.tv_usec
= waitmsecs
;
205 if (tryTimes
== 0 && waitmsecs
== 0)
207 timeout
.tv_sec
= Conf::config
.getMutexSecs();
208 timeout
.tv_usec
= Conf::config
.getMutexUSecs();
209 tryTimes
= Conf::config
.getMutexRetries();
212 while (tries
< tryTimes
)
214 #if defined(sparc) || defined(i686) || defined (x86_64)
215 if (Conf::config
.getNoOfProcessors() >1) {
220 printDebug(DM_Mutex
, "tryLock:%x %s acquired times:%d lock:%d", this, name
, cnt
, lock
);
224 if (cnt
== tryTimes
* 100) break;
227 if (TSL(&lock
) == 0) {
228 printDebug(DM_Mutex
, "tryLock:%x %s acquired times:%d lock:%d", this, name
, cnt
, lock
);
233 ret
= pthread_mutex_trylock(&mutex_
);
234 if (EBUSY
!= ret
) return 0;
237 os::select(0, 0, 0, 0, &timeout
);
240 printDebug(DM_Mutex
, "Unable to get the mutex %x %s, val:%d tried %d times", this, name
, lock
, tries
);
244 int Mutex::getLock(int procSlot
, bool procAccount
)
247 #if defined(sparc) || defined(i686) || defined (x86_64)
249 //add it to the has_ of the ThreadInfo
250 if (ret
==0 && procAccount
) ProcessManager::addMutex(this, procSlot
);
254 ret
= pthread_mutex_lock(&mutex_
);
256 if (ret
== 0) return 0;
261 int Mutex::releaseLock(int procSlot
, bool procAccount
)
264 #if defined(sparc) || defined(i686) || defined (x86_64)
266 if (*lw == 0) return 0;
267 __asm__ __volatile__("movl $0, %%eax; xchgl (%%ecx), %%eax" :
273 //TEMP::PRABA:TODO::CHANGE IT TO CAS
275 ret
= pthread_mutex_unlock(&mutex_
);
277 printDebug(DM_Mutex
, "releaseLock:%x %s lock:%d", this, name
, lock
);
279 if (ret
== 0 && procAccount
)
281 ProcessManager::removeMutex(this, procSlot
);
288 int Mutex::getShareLock(int procSlot
, bool procAccount
)
291 #if defined(sparc) || defined(i686) || defined (x86_64)
292 ret
= tryShareLock(0,0,true,false);
293 //add it to the has_ of the ThreadInfo
294 if (ret
==0 && procAccount
) ProcessManager::addMutex(this, procSlot
);
298 ret
= pthread_mutex_lock(&mutex_
);
300 if (ret
== 0) return 0;
305 int Mutex::getExclusiveLock(int procSlot
, bool procAccount
, bool upgrade
)
308 #if defined(sparc) || defined(i686) || defined (x86_64)
309 ret
= tryShareLock(0,0,false,upgrade
);
310 //add it to the has_ of the ThreadInfo
311 if (ret
==0 && procAccount
) ProcessManager::addMutex(this, procSlot
);
315 ret
= pthread_mutex_lock(&mutex_
);
317 if (ret
== 0) return 0;
322 int Mutex::releaseShareLock(int procSlot
, bool procAccount
)
325 #if defined(sparc) || defined(i686) || defined (x86_64)
326 int oldValue
= (int)lock
;
329 ret
= CAS((int*)&lock
, oldValue
, oldValue
-1 );
331 if( oldValue
== 1 || oldValue
== -1 )
333 ret
= CAS((int*)&lock
, oldValue
, 0 );
338 struct timeval timeout
;
339 timeout
.tv_sec
= Conf::config
.getMutexSecs();
340 timeout
.tv_usec
= Conf::config
.getMutexUSecs();
341 int tryTimes
= Conf::config
.getMutexRetries();
342 while (tries
< tryTimes
)
344 oldValue
= (int)lock
;
346 ret
= CAS((int*)&lock
, oldValue
, (*(int*)&lock
)-1 );
349 if( oldValue
== 1 || oldValue
== -1 )
351 ret
= CAS((int*)&lock
, oldValue
, 0 );
358 ret
= pthread_mutex_unlock(&mutex_
);
361 if (ret
== 0 && procAccount
)
363 ProcessManager::removeMutex(this, procSlot
);
372 #if defined(sparc) || defined(i686) || defined (x86_64)
374 return pthread_mutex_destroy(&mutex_
);
379 int Mutex::recoverMutex()
382 #if defined(sparc) || defined(i686) || defined (x86_64)
384 if (*lw == 0) return 0;
385 __asm__ __volatile__("movl $0, %%eax; xchgl (%%ecx), %%eax" :
392 ret
= pthread_mutex_unlock(&mutex_
);
397 int Mutex::CASGen(volatile void *ptr
, InUse oldVal
, InUse newVal
)
399 #if defined(__sparcv9)
400 CASL((InUse
*) ptr
, oldVal
, newVal
);
403 CAS((InUse
*) ptr
, oldVal
, newVal
);
408 int Mutex::CASL(volatile long *ptr
, long oldVal
, long newVal
)
411 #if defined(__sparcv9) || defined(x86_64) || defined (__x86_64)
412 unsigned long res
= atomic_cas_64((unsigned long*)ptr
,
413 (unsigned long) oldVal
, (unsigned long) newVal
);
414 if (res
== oldVal
) return 0; else return 1;
416 return CAS((int*)ptr
, (int)oldVal
, (int)newVal
);
419 #if defined(LINUX) || defined (FreeBSD)
422 __asm__
__volatile__ ("lock; cmpxchgq %q2, %1"
423 : "=a" (result
), "=m" (*ptr
)
424 : "r" (newVal
), "m" (*ptr
), "0" (oldVal
));
425 if (result
== oldVal
) return 0;
427 struct timeval timeout
;
429 timeout
.tv_usec
=1000;
430 os::select(0,0,0,0, &timeout
);
431 __asm__
__volatile__ ("lock; cmpxchgq %q2, %1"
432 : "=a" (result
), "=m" (*ptr
)
433 : "r" (newVal
), "m" (*ptr
), "0" (oldVal
));
435 //if (result) return 0; else {printf("DEBUG::CAS Fails %d-\n", result); return 1; }
436 if (result
== oldVal
) return 0; else return 1;
438 return CAS((int*)ptr
, (int)oldVal
, (int)newVal
);
442 //TODO:: 64 bit support not done.simply routed to CAS
443 //printf("WINDOWS CASL routed to CAS\n");
444 return CAS((int*)ptr
, (int)oldVal
, (int)newVal
);
447 int Mutex::CAS(volatile int *ptr
, int oldVal
, int newVal
)
449 #if defined(LINUX) || defined (FreeBSD)
451 __asm__
__volatile__ (
455 : "=q" (ret
), "=m" (*ptr
)
456 : "r" (newVal
), "m" (*ptr
), "a" (oldVal
)
459 //above assembly returns 0 in case of failure
462 struct timeval timeout
;
464 timeout
.tv_usec
=1000;
465 os::select(0,0,0,0, &timeout
);
466 __asm__
__volatile__ (
470 : "=q" (ret
), "=m" (*ptr
)
471 : "r" (newVal
), "m" (*ptr
), "a" (oldVal
)
473 //if (ret) return 0; else {printf("DEBUG::CAS Fails %d-\n", ret); return 1; }
474 if (ret
) return 0; else return 1;
475 #elif defined SOLARIS //for solaris
477 ret
= atomic_cas_32((unsigned int*)ptr
, (unsigned int) oldVal
,
478 (unsigned int) newVal
);
479 if (ret
== oldVal
) return 0; else return 1;
481 printf("WINDOWS Mutex::CAS not implemented\n");