adding test scripts
[csql.git] / src / storage / Mutex.cxx
blob14c231df2e1cb8562fe7da4dace2fcbb11540268
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 #endif
120 #endif
121 int Mutex::tryShareLock(int tryTimes, int waitmsecs,bool share, bool upgrade)
123 int ret=0;
124 int oldValue = (int)lock;
125 if (oldValue >= 0 && share){
126 ret = CAS((int*)&lock, oldValue, oldValue+1);
127 }else if ((oldValue == 1 && upgrade ) || ( !share && oldValue == 0) ){
128 ret = CAS((int*)&lock, oldValue, -1);
129 }else { ret = 1;}
130 if (0 == ret) return 0;
131 int tries = 1;
132 struct timeval timeout;
133 timeout.tv_sec = 0;
134 timeout.tv_usec = waitmsecs;
135 if (tryTimes == 0 && waitmsecs == 0)
137 timeout.tv_sec = Conf::config.getMutexSecs();
138 timeout.tv_usec = Conf::config.getMutexUSecs();
139 tryTimes = Conf::config.getMutexRetries();
141 int cnt=0;
142 while (tries < tryTimes)
144 #if defined(sparc) || defined(i686) || defined (x86_64)
145 if (Conf::config.getNoOfProcessors() >1) {
146 cnt=0;
147 while(true) {
148 oldValue = (int)lock;
149 if (oldValue >= 0 && share) {
150 ret = CAS((int*)&lock, oldValue, oldValue+1);
151 }else if ((oldValue == 1 && upgrade ) || (!share && oldValue == 0) ) {
152 ret = CAS((int*)&lock, oldValue, -1);
153 }else { ret = 1; }
155 if(0 == ret ) return 0;
156 cnt++;
157 if (cnt == tryTimes * 100) break;
159 }else {
160 oldValue = (int)lock;
161 if (oldValue >= 0 && share) {
162 ret = CAS((int*)&lock, oldValue, oldValue+1);
163 }else if ((oldValue == 1 && upgrade ) || (!share && oldValue == 0) ){
164 ret = CAS((int*)&lock, oldValue, -1);
165 } else { ret =1;}
166 if(ret==0) return 0;
168 #else
169 ret = pthread_mutex_trylock(&mutex_);
170 if (EBUSY != ret) return 0;
172 #endif
173 os::select(0, 0, 0, 0, &timeout);
174 tries++;
176 //printError(ErrLockTimeOut, "Unable to get the mutex %s, tried %d times", name,tries);
177 return 1;
180 int Mutex::tryLock(int tryTimes, int waitmsecs)
182 if (TSL(&lock) == 0)
184 return 0;
186 int tries = 1;
187 int ret = 0;
188 struct timeval timeout;
189 timeout.tv_sec = 0;
190 timeout.tv_usec = waitmsecs;
191 if (tryTimes == 0 && waitmsecs == 0)
193 timeout.tv_sec = Conf::config.getMutexSecs();
194 timeout.tv_usec = Conf::config.getMutexUSecs();
195 tryTimes = Conf::config.getMutexRetries();
197 int cnt=0;
198 while (tries < tryTimes)
200 #if defined(sparc) || defined(i686) || defined (x86_64)
201 if (Conf::config.getNoOfProcessors() >1) {
202 cnt=0;
203 while(true) {
204 if (TSL(&lock) == 0)
206 return 0;
208 cnt++;
209 if (cnt == tryTimes * 100) break;
211 }else {
212 if (TSL(&lock) == 0) return 0;
214 #else
215 ret = pthread_mutex_trylock(&mutex_);
216 if (EBUSY != ret) return 0;
218 #endif
219 os::select(0, 0, 0, 0, &timeout);
220 tries++;
222 //printError(ErrLockTimeOut, "Unable to get the mutex %s, val:%d tried %d times", name, lock, tries);
223 return 1;
226 int Mutex::getLock(int procSlot, bool procAccount)
228 int ret=0;
229 #if defined(sparc) || defined(i686) || defined (x86_64)
230 ret = tryLock();
231 //add it to the has_ of the ThreadInfo
232 if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot);
234 return ret;
235 #else
236 ret = pthread_mutex_lock(&mutex_);
237 #endif
238 if (ret == 0) return 0;
239 else
240 return 1;
243 int Mutex::releaseLock(int procSlot, bool procAccount)
245 int ret=0;
246 #if defined(sparc) || defined(i686) || defined (x86_64)
247 /*int *lw = &lock;
248 if (*lw == 0) return 0;
249 __asm__ __volatile__("movl $0, %%eax; xchgl (%%ecx), %%eax" :
250 "=m" (*lw) :
251 "ecx" (lw) :
252 "eax");
254 lock = 0;
255 //TEMP::PRABA:TODO::CHANGE IT TO CAS
256 #else
257 ret = pthread_mutex_unlock(&mutex_);
258 #endif
259 if (ret == 0 && procAccount)
261 ProcessManager::removeMutex(this, procSlot);
262 return ret;
264 else
265 return 1;
268 int Mutex::getShareLock(int procSlot, bool procAccount)
270 int ret=0;
271 #if defined(sparc) || defined(i686) || defined (x86_64)
272 ret = tryShareLock(0,0,true,false);
273 //add it to the has_ of the ThreadInfo
274 if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot);
275 return ret;
276 #else
277 ret = pthread_mutex_lock(&mutex_);
278 #endif
279 if (ret == 0) return 0;
280 else
281 return 1;
284 int Mutex::getExclusiveLock(int procSlot, bool procAccount, bool upgrade)
286 int ret=0;
287 #if defined(sparc) || defined(i686) || defined (x86_64)
288 ret = tryShareLock(0,0,false,upgrade);
289 //add it to the has_ of the ThreadInfo
290 if (ret ==0 && procAccount) ProcessManager::addMutex(this, procSlot);
291 return ret;
292 #else
293 ret = pthread_mutex_lock(&mutex_);
294 #endif
295 if (ret == 0) return 0;
296 else
297 return 1;
300 int Mutex::releaseShareLock(int procSlot, bool procAccount)
302 int ret=0;
303 #if defined(sparc) || defined(i686) || defined (x86_64)
304 int oldValue = (int)lock;
305 if( oldValue > 1)
307 ret = CAS((int*)&lock, oldValue, oldValue-1 );
309 if( oldValue == 1 || oldValue == -1 )
311 ret = CAS((int*)&lock, oldValue, 0 );
313 if( ret != 0)
315 int tries = 1;
316 struct timeval timeout;
317 timeout.tv_sec = Conf::config.getMutexSecs();
318 timeout.tv_usec = Conf::config.getMutexUSecs();
319 int tryTimes = Conf::config.getMutexRetries();
320 while (tries < tryTimes)
322 oldValue = (int)lock;
323 if( oldValue > 1){
324 ret = CAS((int*)&lock, oldValue, (*(int*)&lock)-1 );
325 if(ret == 0) break;
327 if( oldValue == 1 || oldValue == -1 )
329 ret = CAS((int*)&lock, oldValue, 0 );
330 if(ret == 0) break;
332 tries++;
335 #else
336 ret = pthread_mutex_unlock(&mutex_);
337 #endif
338 if (ret == 0 && procAccount )
340 ProcessManager::removeMutex(this, procSlot);
341 return ret;
343 else
344 return 1;
347 int Mutex::destroy()
349 #if defined(sparc) || defined(i686) || defined (x86_64)
350 #else
351 return pthread_mutex_destroy(&mutex_);
352 #endif
353 return 0;
356 int Mutex::recoverMutex()
358 int ret=0;
359 #if defined(sparc) || defined(i686) || defined (x86_64)
360 /*int *lw = &lock;
361 if (*lw == 0) return 0;
362 __asm__ __volatile__("movl $0, %%eax; xchgl (%%ecx), %%eax" :
363 "=m" (*lw) :
364 "ecx" (lw) :
365 "eax");
367 lock = 0;
368 #else
369 ret = pthread_mutex_unlock(&mutex_);
370 #endif
371 return ret;
374 int Mutex::CASGen(void *ptr, InUse oldVal, InUse newVal)
376 #if defined(__sparcv9)
377 CASL((InUse *) ptr, oldVal, newVal);
378 #else
379 CAS((InUse *) ptr, oldVal, newVal);
380 #endif
383 int Mutex::CASL(long *ptr, long oldVal, long newVal)
385 #ifdef SOLARIS
386 #if defined(__sparcv9) || defined(x86_64) || defined (__x86_64)
387 unsigned long res = atomic_cas_64((unsigned long*)ptr,
388 (unsigned long) oldVal, (unsigned long) newVal);
389 if (res == oldVal) return 0; else return 1;
390 #else
391 return CAS((int*)ptr, (int)oldVal, (int)newVal);
392 #endif
393 #endif
394 #if defined(LINUX) || defined (FreeBSD)
395 #ifdef x86_64
396 long result;
397 __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
398 : "=a" (result), "=m" (*ptr)
399 : "r" (newVal), "m" (*ptr), "0" (oldVal));
400 if (result == oldVal) return 0;
402 struct timeval timeout;
403 timeout.tv_sec=0;
404 timeout.tv_usec=1000;
405 os::select(0,0,0,0, &timeout);
406 __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
407 : "=a" (result), "=m" (*ptr)
408 : "r" (newVal), "m" (*ptr), "0" (oldVal));
410 //if (result) return 0; else {printf("DEBUG::CAS Fails %d-\n", result); return 1; }
411 if (result == oldVal) return 0; else return 1;
412 #else
413 return CAS((int*)ptr, (int)oldVal, (int)newVal);
414 #endif
415 #endif
418 int Mutex::CAS(int *ptr, int oldVal, int newVal)
420 #if defined(LINUX) || defined (FreeBSD)
421 unsigned char ret;
422 __asm__ __volatile__ (
423 " lock\n"
424 " cmpxchgl %2,%1\n"
425 " sete %0\n"
426 : "=q" (ret), "=m" (*ptr)
427 : "r" (newVal), "m" (*ptr), "a" (oldVal)
428 : "memory");
430 //above assembly returns 0 in case of failure
431 if (ret) return 0;
433 struct timeval timeout;
434 timeout.tv_sec=0;
435 timeout.tv_usec=1000;
436 os::select(0,0,0,0, &timeout);
437 __asm__ __volatile__ (
438 " lock\n"
439 " cmpxchgl %2,%1\n"
440 " sete %0\n"
441 : "=q" (ret), "=m" (*ptr)
442 : "r" (newVal), "m" (*ptr), "a" (oldVal)
443 : "memory");
444 //if (ret) return 0; else {printf("DEBUG::CAS Fails %d-\n", ret); return 1; }
445 if (ret) return 0; else return 1;
446 #else //for solaris
447 unsigned int ret;
448 ret = atomic_cas_32((unsigned int*)ptr, (unsigned int) oldVal,
449 (unsigned int) newVal);
450 if (ret == oldVal) return 0; else return 1;
451 #endif