changing lock bucket size
[csql.git] / src / storage / Mutex.cxx
blobd2637be61aaf677dbec61775638408156752cd93
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 pSlot = -1;
47 return 0;
49 int Mutex::init(char *mname)
51 init();
52 if (strlen(mname) > 19 ) {
53 printError(ErrNote, "Mutex name cannot exceeed 20 characters\n");
54 return 0;
56 strcpy(name, mname);
57 return 0;
61 #if defined(sparc) || defined(i686) || defined (x86_64)
62 int TSL(volatile Lock *lock)
65 if (lock == 0) {
66 __asm("mov $1, %eax");
67 __asm("mov 20(%ebp), %edx");
68 __asm("xchg %eax, (%edx)");
69 __asm("test %eax %eax");
70 __asm("jnz .L1000");
71 return 0;
72 } else
74 __asm(".L1000:");
75 return 1;
78 /*Was Working in linux
79 char oldval;
80 __asm__ __volatile__(
81 "xchgb %b0,%1"
82 :"=q" (oldval), "=m" (lock)
83 :"0" (0) : "memory");
85 return oldval > 0;
87 #if defined(LINUX) || defined (FreeBSD)
88 int* lw;
89 int res;
90 lw = (int*)lock;
91 if (*lock == 1) return 1;
92 /* This assembly compiles only with -O2 option, and not with -g option. Version1
93 __asm__ __volatile__(
94 "movl $1, %%eax; xchgl (%%ecx), %%eax"
95 : "=eax" (res), "=m" (*lw)
96 : "ecx" (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)
103 : "r" (lock));
107 // This assembly is Version3. Working fine for now
108 __asm__ __volatile__(
109 "xchgl %0, %1 \n\t"
110 : "=r"(res), "=m"(*lock)
111 : "0"(1), "m"(*lock)
112 : "memory");
114 //fprintf(stderr,"after asm %d ret %d\n", *lock, res);
116 return(res);
118 #elif defined (SOLARIS)
119 Lock res;
120 res = atomic_cas_32((unsigned*)lock, 0, 1);
121 return (res);
122 #elif defined (WINNT)
123 printf("WINDOWS TSL not yet implemented\n");
124 return 0;
125 #endif
127 #endif
128 int Mutex::tryShareLock(int tryTimes, int waitmsecs,bool share, bool upgrade)
130 int ret=0;
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);
136 }else { ret = 1;}
137 if (0 == ret) {
138 printDebug(DM_Mutex, "tryShareLock:%x %s acquired lock:%d", this, name,lock);
139 return 0;
141 int tries = 1;
142 struct timeval timeout;
143 timeout.tv_sec = 0;
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();
151 int cnt=0;
152 while (tries < tryTimes)
154 #if defined(sparc) || defined(i686) || defined (x86_64)
155 //if (Conf::config.getNoOfProcessors() >1) {
156 cnt=0;
157 while(true) {
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);
163 }else { ret = 1; }
165 if (0 == ret) {
166 printDebug(DM_Mutex, "tryShareLock:%x %s acquired times:%d lock:%d", this, name, cnt, lock);
167 return 0;
169 cnt++;
170 if (cnt == tryTimes * 100) break;
172 /*}else {
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);
178 } else { ret =1;}
179 if(ret==0) return 0;
181 #else
182 ret = pthread_mutex_trylock(&mutex_);
183 if (EBUSY != ret) return 0;
185 #endif
186 os::select(0, 0, 0, 0, &timeout);
187 tries++;
189 printDebug(DM_Mutex, "Unable to get the mutex %x %s, tried %d times", this, name,tries);
190 return 1;
193 int Mutex::tryLock(int tryTimes, int waitmsecs)
195 if (TSL(&lock) == 0)
197 printDebug(DM_Mutex, "tryLock:%x %s acquired lock:%d", this, name, lock);
198 return 0;
200 int tries = 1;
201 int ret = 0;
202 struct timeval timeout;
203 timeout.tv_sec = 0;
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();
211 int cnt=0;
212 while (tries < tryTimes)
214 #if defined(sparc) || defined(i686) || defined (x86_64)
215 if (Conf::config.getNoOfProcessors() >1) {
216 cnt=0;
217 while(true) {
218 if (TSL(&lock) == 0)
220 printDebug(DM_Mutex, "tryLock:%x %s acquired times:%d lock:%d", this, name, cnt, lock);
221 return 0;
223 cnt++;
224 if (cnt == tryTimes * 100) break;
226 }else {
227 if (TSL(&lock) == 0) {
228 printDebug(DM_Mutex, "tryLock:%x %s acquired times:%d lock:%d", this, name, cnt, lock);
229 return 0;
232 #else
233 ret = pthread_mutex_trylock(&mutex_);
234 if (EBUSY != ret) return 0;
236 #endif
237 os::select(0, 0, 0, 0, &timeout);
238 tries++;
240 printDebug(DM_Mutex, "Unable to get the mutex %x %s, val:%d tried %d times", this, name, lock, tries);
241 return 1;
244 int Mutex::getLock(int procSlot, bool procAccount)
246 int ret=0;
247 #if defined(sparc) || defined(i686) || defined (x86_64)
248 ret = tryLock();
249 //add it to the has_ of the ThreadInfo
250 if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot);
251 pSlot = procSlot;
252 return ret;
253 #else
254 ret = pthread_mutex_lock(&mutex_);
255 #endif
256 if (ret == 0) return 0;
257 else
258 return 1;
261 int Mutex::releaseLock(int procSlot, bool procAccount)
263 int ret=0;
264 #if defined(sparc) || defined(i686) || defined (x86_64)
265 /*int *lw = &lock;
266 if (*lw == 0) return 0;
267 __asm__ __volatile__("movl $0, %%eax; xchgl (%%ecx), %%eax" :
268 "=m" (*lw) :
269 "ecx" (lw) :
270 "eax");
272 lock = 0;
273 //TEMP::PRABA:TODO::CHANGE IT TO CAS
274 #else
275 ret = pthread_mutex_unlock(&mutex_);
276 #endif
277 printDebug(DM_Mutex, "releaseLock:%x %s lock:%d", this, name, lock);
278 pSlot = -1;
279 if (ret == 0 && procAccount)
281 ProcessManager::removeMutex(this, procSlot);
282 return ret;
284 else
285 return 1;
288 int Mutex::getShareLock(int procSlot, bool procAccount)
290 int ret=0;
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);
295 pSlot = procSlot;
296 return ret;
297 #else
298 ret = pthread_mutex_lock(&mutex_);
299 #endif
300 if (ret == 0) return 0;
301 else
302 return 1;
305 int Mutex::getExclusiveLock(int procSlot, bool procAccount, bool upgrade)
307 int ret=0;
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);
312 pSlot = procSlot;
313 return ret;
314 #else
315 ret = pthread_mutex_lock(&mutex_);
316 #endif
317 if (ret == 0) return 0;
318 else
319 return 1;
322 int Mutex::releaseShareLock(int procSlot, bool procAccount)
324 int ret=0;
325 #if defined(sparc) || defined(i686) || defined (x86_64)
326 int oldValue = (int)lock;
327 if( oldValue > 1)
329 ret = CAS((int*)&lock, oldValue, oldValue-1 );
331 if( oldValue == 1 || oldValue == -1 )
333 ret = CAS((int*)&lock, oldValue, 0 );
335 if( ret != 0)
337 int tries = 1;
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;
345 if( oldValue > 1){
346 ret = CAS((int*)&lock, oldValue, (*(int*)&lock)-1 );
347 if(ret == 0) break;
349 if( oldValue == 1 || oldValue == -1 )
351 ret = CAS((int*)&lock, oldValue, 0 );
352 if(ret == 0) break;
354 tries++;
357 #else
358 ret = pthread_mutex_unlock(&mutex_);
359 #endif
360 pSlot = -1;
361 if (ret == 0 && procAccount )
363 ProcessManager::removeMutex(this, procSlot);
364 return ret;
366 else
367 return 1;
370 int Mutex::destroy()
372 #if defined(sparc) || defined(i686) || defined (x86_64)
373 #else
374 return pthread_mutex_destroy(&mutex_);
375 #endif
376 return 0;
379 int Mutex::recoverMutex()
381 int ret=0;
382 #if defined(sparc) || defined(i686) || defined (x86_64)
383 /*int *lw = &lock;
384 if (*lw == 0) return 0;
385 __asm__ __volatile__("movl $0, %%eax; xchgl (%%ecx), %%eax" :
386 "=m" (*lw) :
387 "ecx" (lw) :
388 "eax");
390 lock = 0;
391 #else
392 ret = pthread_mutex_unlock(&mutex_);
393 #endif
394 return ret;
397 int Mutex::CASGen(volatile void *ptr, InUse oldVal, InUse newVal)
399 #if defined(__sparcv9)
400 CASL((InUse *) ptr, oldVal, newVal);
401 return 0;
402 #else
403 CAS((InUse *) ptr, oldVal, newVal);
404 return 0;
405 #endif
408 int Mutex::CASL(volatile long *ptr, long oldVal, long newVal)
410 #ifdef SOLARIS
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;
415 #else
416 return CAS((int*)ptr, (int)oldVal, (int)newVal);
417 #endif
418 #endif
419 #if defined(LINUX) || defined (FreeBSD)
420 #ifdef x86_64
421 long result;
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;
428 timeout.tv_sec=0;
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;
437 #else
438 return CAS((int*)ptr, (int)oldVal, (int)newVal);
439 #endif
440 #endif
441 #ifdef WINNT
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);
445 #endif
447 int Mutex::CAS(volatile int *ptr, int oldVal, int newVal)
449 #if defined(LINUX) || defined (FreeBSD)
450 unsigned char ret;
451 __asm__ __volatile__ (
452 " lock\n"
453 " cmpxchgl %2,%1\n"
454 " sete %0\n"
455 : "=q" (ret), "=m" (*ptr)
456 : "r" (newVal), "m" (*ptr), "a" (oldVal)
457 : "memory");
459 //above assembly returns 0 in case of failure
460 if (ret) return 0;
462 struct timeval timeout;
463 timeout.tv_sec=0;
464 timeout.tv_usec=1000;
465 os::select(0,0,0,0, &timeout);
466 __asm__ __volatile__ (
467 " lock\n"
468 " cmpxchgl %2,%1\n"
469 " sete %0\n"
470 : "=q" (ret), "=m" (*ptr)
471 : "r" (newVal), "m" (*ptr), "a" (oldVal)
472 : "memory");
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
476 unsigned int ret;
477 ret = atomic_cas_32((unsigned int*)ptr, (unsigned int) oldVal,
478 (unsigned int) newVal);
479 if (ret == oldVal) return 0; else return 1;
480 #elif defined WINNT
481 printf("WINDOWS Mutex::CAS not implemented\n");
482 return 0;
483 #endif