00001 /* 00002 * Copyright (c) 1998 by Tech Soft 3D, LLC. 00003 * The information contained herein is confidential and proprietary to 00004 * Tech Soft 3D, LLC., and considered a trade secret as defined under 00005 * civil and criminal statutes. Tech Soft 3D shall pursue its civil 00006 * and criminal remedies in the event of unauthorized use or misappropriation 00007 * of its trade secrets. Use of this information by anyone other than 00008 * authorized employees of Tech Soft 3D, LLC. is granted only under a 00009 * written non-disclosure agreement, expressly prescribing the scope and 00010 * manner of such use. 00011 * 00012 * $Id: hmutex_8h-source.html,v 1.29 2008-03-10 07:09:28 stage Exp $ 00013 */ 00014 00015 #ifndef HOOPS_MUTEX_DEFINED 00016 #define HOOPS_MUTEX_DEFINED 00017 00018 /* Note: if the read/write lock is needed, 00019 00020 #define HMUTEX_IMPLEMENT_FUNCTIONS 00021 00022 in one module that includes this header to generate the code components 00023 */ 00024 00025 #ifndef POINTER_SIZED_INT 00026 #if defined(_M_IA64) || defined(_M_AMD64) || defined(WIN64) || defined(_WIN64) || defined(_M_X64) 00027 # define HMUTEX_POINTER_SIZED_INT __int64 00028 # else 00029 # define HMUTEX_POINTER_SIZED_INT long 00030 # endif 00031 #else 00032 # define HMUTEX_POINTER_SIZED_INT POINTER_SIZED_INT 00033 #endif 00034 00035 typedef unsigned HMUTEX_POINTER_SIZED_INT HThreadID; /* unique thread identifier */ 00036 typedef void * HMutex; /* exclusive (single thread) access */ 00037 typedef void * HRWLock; /* multiple readers, exclusive writer */ 00038 00039 #ifdef _MSC_VER 00040 #include <time.h> 00041 #define MILLI_SECOND_SLEEP(_x_) Sleep(_x_) 00042 #else 00043 #ifndef __USE_POSIX199309 00044 #define __USE_POSIX199309 00045 #endif 00046 #include <time.h> 00047 #define MILLI_SECOND_SLEEP(_x_) do { \ 00048 struct timespec req; \ 00049 unsigned long _xx_ = (unsigned long)_x_; \ 00050 req.tv_sec = _xx_/1000; \ 00051 req.tv_nsec = ((_xx_%1000)*1000000); \ 00052 nanosleep(&req,0); \ 00053 } while (0); 00054 #endif 00055 00056 00057 #ifdef DISABLE_MUTEX 00058 00059 # define THREAD_ID() 0 00060 00061 # define CREATE_MUTEX(_m_) _m_ = (void *)(~0) /* non-null */ 00062 # define LOCK_MUTEX(_m_) (void)(_m_) 00063 # define UNLOCK_MUTEX(_m_) (void)(_m_) 00064 # define DESTROY_MUTEX(_m_) _m_ = 0 00065 00066 # define CREATE_LOCK(_l_) CREATE_MUTEX(_l_) 00067 # define READ_LOCK(_l_) LOCK_MUTEX(_l_) 00068 # define WRITE_LOCK(_l_) LOCK_MUTEX(_l_) 00069 # define UNLOCK_LOCK(_l_) UNLOCK_MUTEX(_l_) 00070 # define DESTROY_LOCK(_l_) DESTROY_MUTEX(_l_) 00071 00072 # define HM_Semaphore HMutex 00073 00074 # define HM_CONSTRUCT_SEMAPHORE(_s_, _l_, _v_) _s_ = (void *)(~0) 00075 # define HM_DESTRUCT_SEMAPHORE(_s_) _s_ = 0 00076 # define HM_RELEASE_SEMAPHORE(_s_, _n_) (void)(_s_) 00077 # define HM_WAIT_SEMAPHORE(_s_) (void)(_s_) 00078 00079 # define THREAD_FUNCTION(_funct_) \ 00080 EXTERNAL unsigned int __stdcall _hthread_##_funct_(void *); \ 00081 EXTERNAL unsigned int __stdcall _hthread_##_funct_(void * _thread_data_) 00082 # define THREAD_FUNCTION_DATA(_cast_) (_cast_)_thread_data_ 00083 # define THREAD_FUNCTION_CALL(_funct_,_data_) _hthread_##_funct_((void*)_data_) 00084 00085 00086 #ifndef _WIN32_WCE 00087 # define CREATE_THREAD(_id_,_funct_,_data_) #error threading disabled in build 00088 # define JOIN_THREAD(_id_) #error threading disabled in build 00089 #else 00090 # define CREATE_THREAD(_id_,_funct_,_data_) 00091 # define JOIN_THREAD(_id_) 00092 #endif 00093 00094 #else 00095 00096 #include <string.h> 00097 00098 #ifndef ALLOCATE_MEMORY /* simple memory handling if not building inside HOOPS */ 00099 # include <stdlib.h> 00100 # define ALLOCATE_MEMORY(p,t) p = (t *)malloc(sizeof(t)) 00101 # define FREE_MEMORY(p,t) (void)sizeof(t),free(p) 00102 # define ALLOCATE_MEMORY_ARRAY(p,c,t) p = (t *)malloc((c)*sizeof(t)) 00103 # define FREE_MEMORY_ARRAY(p,c,t) (void)c,(void)sizeof(t),free(p) 00104 #endif 00105 00106 00107 #ifndef HMUTEX_INITIAL_THREADS 00108 # define HMUTEX_INITIAL_THREADS 8 00109 #endif 00110 #ifndef HMUTEX_MAX_CONCURRENT_READERS 00111 # define HMUTEX_MAX_CONCURRENT_READERS 4096 00112 #endif 00113 00114 #ifndef HMUTEX_ERROR 00115 # include <stdio.h> 00116 # define HMUTEX_ERROR(_tag_) printf ("%s\n", _tag_) 00117 #endif 00118 00119 /* use -DH_MUTEX_DEBUG_TRACE -DH_RW_LOCK_DEBUG_TRACE -DH_RW_LOCK_DEBUG_TRACE_INTERNAL */ 00120 #if defined(H_MUTEX_DEBUG_TRACE) || defined(H_RW_LOCK_DEBUG_TRACE) || defined(H_RW_LOCK_DEBUG_TRACE_INTERNAL) 00121 # include <stdio.h> 00122 00123 # ifndef H_MUTEX_DEBUG_TRACE_FILE_NAME 00124 # define H_MUTEX_DEBUG_TRACE_FILE_NAME "hmutex_debug_trace_file.txt" 00125 # endif 00126 00127 # define _H_DEBUG_TRACE(_tag_,_id_,_synch_,_lock_details_,_lines_) do{ \ 00128 FILE *hmutex_debug_trace_file = fopen(H_MUTEX_DEBUG_TRACE_FILE_NAME,"a+"); \ 00129 if (hmutex_debug_trace_file != 0) { \ 00130 fprintf (hmutex_debug_trace_file, "%p %p %s", (void*)_id_, (void*)_synch_, _tag_); \ 00131 if (_lock_details_) {\ 00132 HM_Lock * ll = (HM_Lock *)_synch_; \ 00133 fprintf (hmutex_debug_trace_file, " (ar: %d pr: %d aw: %d pw: %d at: %d)", \ 00134 ll->active_readers, ll->pending_readers, ll->active_writers, ll->pending_writers, \ 00135 ll->active_threads); \ 00136 } \ 00137 if (_lines_) \ 00138 fprintf (hmutex_debug_trace_file, " %s %d", __FILE__, __LINE__); \ 00139 fprintf (hmutex_debug_trace_file, "\n"); \ 00140 fclose (hmutex_debug_trace_file); \ 00141 } else { \ 00142 fprintf(stderr, "opening %s failed.\n", H_MUTEX_DEBUG_TRACE_FILE_NAME); \ 00143 } \ 00144 } while (0) 00145 #endif 00146 00147 #ifdef H_MUTEX_DEBUG_TRACE 00148 # define _H_MUTEX_DEBUG_TRACE(_tag_,_id_,_synch_) _H_DEBUG_TRACE(_tag_,_id_,_synch_,0,1) 00149 #else 00150 # define _H_MUTEX_DEBUG_TRACE(_tag_,_id_,_synch_) (void)_tag_,(void)_id_,(void)_synch_ 00151 #endif 00152 00153 #ifdef H_RW_LOCK_DEBUG_TRACE 00154 # define _H_RW_LOCK_DEBUG_TRACE(_tag_,_id_,_synch_,_d_) _H_DEBUG_TRACE(_tag_,_id_,_synch_,_d_,1) 00155 #else 00156 # define _H_RW_LOCK_DEBUG_TRACE(_tag_,_id_,_synch_,_d_) (void)_tag_,(void)_id_,(void)_synch_,(void)_d_ 00157 #endif 00158 00159 #ifdef H_RW_LOCK_DEBUG_TRACE_INTERNAL 00160 # define _H_RW_LOCK_DEBUG_TRACE_INTERNAL(_tag_,_id_,_synch_,_d_) _H_DEBUG_TRACE(_tag_,_id_,_synch_,_d_,0) 00161 #else 00162 # define _H_RW_LOCK_DEBUG_TRACE_INTERNAL(_tag_,_id_,_synch_,_d_) (void)_tag_,(void)_id_,(void)_synch_,(void)_d_ 00163 #endif 00164 00165 00166 #ifndef GLOBAL_FUNCTION 00167 # ifdef __cplusplus 00168 # define GLOBAL_FUNCTION extern "C" 00169 # define EXTERNAL extern "C" 00170 # else 00171 # define GLOBAL_FUNCTION /* (default) */ 00172 # define EXTERNAL extern 00173 # endif 00174 #endif 00175 #ifndef HM_CDECL 00176 # define HM_CDECL 00177 #endif 00178 00179 00180 #ifdef _MSC_VER 00181 # ifndef WIN32_LEAN_AND_MEAN 00182 # define WIN32_LEAN_AND_MEAN 00183 # endif 00184 # include <windows.h> 00185 # include <process.h> 00186 # ifndef HM_CDECL 00187 # define HM_CDECL __cdecl 00188 # endif 00189 00190 # define THREAD_ID() (HThreadID)GetCurrentThreadId() 00191 00192 # define HM_Semaphore HANDLE 00193 00194 # define HM_CONSTRUCT_SEMAPHORE(_s_, _l_, _v_) _s_ = CreateSemaphore (0, _v_, _l_, 0) 00195 # define HM_DESTRUCT_SEMAPHORE(_s_) CloseHandle (_s_) 00196 # define HM_RELEASE_SEMAPHORE(_s_, _n_) ReleaseSemaphore (_s_, _n_, 0) 00197 # define HM_WAIT_SEMAPHORE(_s_) WaitForSingleObject (_s_, INFINITE) 00198 00199 # define CREATE_THREAD(_id_,_funct_,_data_) _id_ = (HThreadID) _beginthreadex(NULL, 0, _hthread_##_funct_, (void*)_data_, 0, NULL); 00200 # define JOIN_THREAD(_id_) do { \ 00201 WaitForSingleObject((HANDLE)_id_, INFINITE); \ 00202 CloseHandle((HANDLE)_id_); \ 00203 }while (0) 00204 00205 #define USE_CRITICAL_SECTION_MUTEX 00206 00207 #ifdef USE_CRITICAL_SECTION_MUTEX 00208 # define CREATE_MUTEX(_m_) \ 00209 do { \ 00210 CRITICAL_SECTION * cs; \ 00211 ALLOCATE_MEMORY (cs, CRITICAL_SECTION); \ 00212 InitializeCriticalSection (cs); \ 00213 _m_ = (void *)cs; \ 00214 } while (0) 00215 # define LOCK_MUTEX(_m_) \ 00216 EnterCriticalSection ((CRITICAL_SECTION *)_m_) 00217 # define UNLOCK_MUTEX(_m_) \ 00218 LeaveCriticalSection ((CRITICAL_SECTION *)_m_) 00219 # define DESTROY_MUTEX(_m_) \ 00220 do { \ 00221 CRITICAL_SECTION * cs; \ 00222 cs = (CRITICAL_SECTION *)_m_; \ 00223 DeleteCriticalSection (cs); \ 00224 FREE_MEMORY (cs, CRITICAL_SECTION); \ 00225 _m_ = 0; \ 00226 } while (0) 00227 #endif 00228 #ifdef USE_INTERLOCK_MUTEX 00229 #include <intrin.h> 00230 00231 typedef struct { 00232 volatile long use_count; 00233 HThreadID thread; 00234 } Interlock_Mutex; 00235 00236 /* small enough to use macros */ 00237 #define CREATE_MUTEX(_m_) \ 00238 do { \ 00239 Interlock_Mutex * _hm_; \ 00240 ALLOCATE_MEMORY (_hm_, Interlock_Mutex); \ 00241 memset (_hm_, 0, sizeof (Interlock_Mutex)); \ 00242 _m_ = (void *)_hm_; \ 00243 _H_MUTEX_DEBUG_TRACE("CREATE_MUTEX:",THREAD_ID(),_m_); \ 00244 } while (0) 00245 #define DESTROY_MUTEX(_m_) \ 00246 do { \ 00247 Interlock_Mutex * _hm_ = (Interlock_Mutex *)_m_; \ 00248 _H_MUTEX_DEBUG_TRACE("DESTROY_MUTEX:",THREAD_ID(),_m_); \ 00249 FREE_MEMORY (_hm_, Interlock_Mutex); \ 00250 _m_ = 0; \ 00251 } while (0) 00252 #define LOCK_MUTEX(_m_) \ 00253 do { \ 00254 Interlock_Mutex * _hm_ = (Interlock_Mutex *)_m_; \ 00255 HThreadID _me_ = THREAD_ID(); \ 00256 if (_hm_->thread != _me_) { \ 00257 _H_MUTEX_DEBUG_TRACE("LOCK_MUTEX: before",_me_,_hm_); \ 00258 while (_InterlockedCompareExchange (&_hm_->use_count, \ 00259 1, 0) != 0) {} \ 00260 _hm_->thread = _me_; \ 00261 _H_MUTEX_DEBUG_TRACE("LOCK_MUTEX: after",_me_,_hm_); \ 00262 } \ 00263 else \ 00264 ++_hm_->use_count; \ 00265 } while (0) 00266 #define UNLOCK_MUTEX(_m_) \ 00267 do { \ 00268 Interlock_Mutex * _hm_ = (Interlock_Mutex *)_m_; \ 00269 HThreadID _me_ = THREAD_ID(); \ 00270 _H_MUTEX_DEBUG_TRACE("UNLOCK_MUTEX: before",_me_,_hm_); \ 00271 if (_hm_->thread != _me_) { \ 00272 _H_MUTEX_DEBUG_TRACE("UNLOCK_MUTEX: failed",_me_,_hm_); \ 00273 HMUTEX_ERROR ("Mutex non-owner release"); \ 00274 } \ 00275 else if (_hm_->use_count > 1) \ 00276 --_hm_->use_count; \ 00277 else { \ 00278 _hm_->thread = 0; \ 00279 _InterlockedExchange(&_hm_->use_count, 0); \ 00280 _H_MUTEX_DEBUG_TRACE("UNLOCK_MUTEX: after",_me_,_hm_); \ 00281 } \ 00282 } while (0) 00283 #endif 00284 00285 00286 # define THREAD_FUNCTION(_funct_) \ 00287 EXTERNAL unsigned int __stdcall _hthread_##_funct_(void *); \ 00288 EXTERNAL unsigned int __stdcall _hthread_##_funct_(void * _thread_data_) 00289 # define THREAD_FUNCTION_DATA(_cast_) (_cast_)_thread_data_ 00290 # define THREAD_FUNCTION_CALL(_funct_,_data_) _hthread_##_funct_((void*)_data_) 00291 00292 #else 00293 # include <pthread.h> 00294 00295 # define THREAD_ID() (HThreadID)pthread_self() 00296 00297 # define CREATE_THREAD(_id_,_funct_,_data_) pthread_create((pthread_t *)&_id_, 0, _hthread_##_funct_, (void*)_data_) 00298 # define JOIN_THREAD(_id_) pthread_join((pthread_t)_id_, 0) 00299 # define THREAD_FUNCTION(_funct_) \ 00300 EXTERNAL void * _hthread_##_funct_(void *); \ 00301 EXTERNAL void * _hthread_##_funct_(void * _thread_data_) 00302 # define THREAD_FUNCTION_DATA(_cast_) (_cast_)_thread_data_ 00303 # define THREAD_FUNCTION_CALL(_funct_,_data_) _hthread_##_funct_((void*)_data_) 00304 00305 #define BAD_SEM_INIT 00306 #ifndef BAD_SEM_INIT 00307 00308 # include <semaphore.h> 00309 # define HM_Semaphore sem_t 00310 00311 # define HM_CONSTRUCT_SEMAPHORE(_s_, _l_, _v_) sem_init (&_s_, 0, _v_) 00312 # define HM_DESTRUCT_SEMAPHORE(_s_) sem_destroy (&_s_) 00313 # define HM_RELEASE_SEMAPHORE(_s_, _n_) do { \ 00314 int _ii_ = _n_; \ 00315 while (_ii_-- > 0) \ 00316 sem_post (&_s_);\ 00317 } while (0) 00318 # define HM_WAIT_SEMAPHORE(_s_) while (0 != sem_wait (&_s_)) 00319 00320 #else 00321 00322 /* semaphore emulation on pthreads */ 00323 typedef struct hm_semaphore_s { 00324 pthread_mutex_t count_lock; 00325 int count; 00326 } HM_Semaphore; 00327 00328 # define HM_CONSTRUCT_SEMAPHORE(_s_, _l_, _v_) do { \ 00329 pthread_mutex_init (&_s_.count_lock, 0); \ 00330 _s_.count = _v_; \ 00331 } while (0) 00332 00333 # define HM_DESTRUCT_SEMAPHORE(_s_) do { \ 00334 pthread_mutex_destroy (&_s_.count_lock); \ 00335 } while (0) 00336 00337 # define HM_RELEASE_SEMAPHORE(_s_, _n_) do { \ 00338 pthread_mutex_lock (&_s_.count_lock); \ 00339 _s_.count += _n_; \ 00340 pthread_mutex_unlock (&_s_.count_lock); \ 00341 } while (0) 00342 00343 # define HM_WAIT_SEMAPHORE(_s_) do { \ 00344 pthread_mutex_lock (&_s_.count_lock); \ 00345 if (_s_.count > 0) { \ 00346 _s_.count--; \ 00347 pthread_mutex_unlock (&_s_.count_lock); \ 00348 break; \ 00349 } \ 00350 pthread_mutex_unlock (&_s_.count_lock); \ 00351 MILLI_SECOND_SLEEP(1); \ 00352 } while (1) 00353 00354 #endif 00355 00356 #endif 00357 00358 00359 00360 #ifndef CREATE_MUTEX 00361 00362 /* Mutex is a simple single (but recursive) access mechanism */ 00363 typedef struct { 00364 HM_Semaphore control; /* single-access "mutex" */ 00365 HThreadID thread; /* thread which has use of this mutex */ 00366 int use_count; /* recursive reference by this thread */ 00367 } HM_Mutex; 00368 00369 /* small enough to use macros */ 00370 #define CREATE_MUTEX(_m_) \ 00371 do { \ 00372 HM_Mutex * _hm_; \ 00373 ALLOCATE_MEMORY (_hm_, HM_Mutex); \ 00374 memset (_hm_, 0, sizeof (HM_Mutex)); \ 00375 HM_CONSTRUCT_SEMAPHORE (_hm_->control, 1, 1); \ 00376 _m_ = (void *)_hm_; \ 00377 _H_MUTEX_DEBUG_TRACE("CREATE_MUTEX:",THREAD_ID(),_m_);\ 00378 } while (0) 00379 #define DESTROY_MUTEX(_m_) \ 00380 do { \ 00381 HM_Mutex * _hm_ = (HM_Mutex *)_m_; \ 00382 _H_MUTEX_DEBUG_TRACE("DESTROY_MUTEX:",THREAD_ID(),_m_);\ 00383 HM_DESTRUCT_SEMAPHORE (_hm_->control); \ 00384 FREE_MEMORY (_hm_, HM_Mutex); \ 00385 _m_ = 0; \ 00386 } while (0) 00387 #define LOCK_MUTEX(_m_) \ 00388 do { \ 00389 HM_Mutex * _hm_ = (HM_Mutex *)_m_; \ 00390 HThreadID _me_ = THREAD_ID(); \ 00391 if (_hm_->thread != _me_) { \ 00392 _H_MUTEX_DEBUG_TRACE("LOCK_MUTEX: before",_me_,_hm_);\ 00393 HM_WAIT_SEMAPHORE (_hm_->control); \ 00394 _hm_->thread = _me_; \ 00395 _H_MUTEX_DEBUG_TRACE("LOCK_MUTEX: after",_me_,_hm_);\ 00396 } \ 00397 ++_hm_->use_count; \ 00398 } while (0) 00399 #define UNLOCK_MUTEX(_m_) \ 00400 do { \ 00401 HM_Mutex * _hm_ = (HM_Mutex *)_m_; \ 00402 HThreadID _me_ = THREAD_ID(); \ 00403 _H_MUTEX_DEBUG_TRACE("UNLOCK_MUTEX: before",_me_,_hm_); \ 00404 if (_hm_->thread != _me_) { \ 00405 _H_MUTEX_DEBUG_TRACE("UNLOCK_MUTEX: failed",_me_,_hm_); \ 00406 HMUTEX_ERROR ("Mutex non-owner release"); \ 00407 } else if (--_hm_->use_count == 0) { \ 00408 _hm_->thread = 0; \ 00409 HM_RELEASE_SEMAPHORE (_hm_->control, 1); \ 00410 _H_MUTEX_DEBUG_TRACE("UNLOCK_MUTEX: after",_me_,_hm_); \ 00411 } \ 00412 } while (0) 00413 00414 #endif 00415 00416 00417 /* Lock is a complex, many reader, single (nested) writer mechanism */ 00418 /* need to simulate complex read/write lock using available objects */ 00419 typedef struct { 00420 HThreadID id; /* thread with any active or pending locks */ 00421 int use_count; /* number of locks for this thread */ 00422 int state; /* each bit on if corresponding lock is for write */ 00423 } HM_Per_Thread; 00424 00425 typedef struct { 00426 HM_Semaphore control, resize; /* single-access "mutex" */ 00427 HM_Semaphore read, write; /* semaphores */ 00428 int active_readers, pending_readers; 00429 int active_writers, pending_writers; 00430 int active_threads, max_threads; 00431 int pending_resizes; 00432 00433 HM_Per_Thread * threads; 00434 } HM_Lock; 00435 00436 00437 #define CREATE_LOCK(_l_) do { \ 00438 _l_ = HM_Create_Lock (HMUTEX_INITIAL_THREADS); \ 00439 _H_RW_LOCK_DEBUG_TRACE("HM_Create_Lock:",THREAD_ID(),_l_,0); \ 00440 } while (0) 00441 #define DESTROY_LOCK(_l_) do { \ 00442 _H_RW_LOCK_DEBUG_TRACE("HM_Destroy_Lock:",THREAD_ID(),_l_,0); \ 00443 _l_ = HM_Destroy_Lock ((HM_Lock *)_l_); \ 00444 } while (0) 00445 #define READ_LOCK(_l_) do { \ 00446 _H_RW_LOCK_DEBUG_TRACE("HM_Read_Lock:",THREAD_ID(),_l_,0); \ 00447 HM_Read_Lock ((HM_Lock *)_l_); \ 00448 } while (0) 00449 #define WRITE_LOCK(_l_) do { \ 00450 _H_RW_LOCK_DEBUG_TRACE("HM_Write_Lock:",THREAD_ID(),_l_,0); \ 00451 HM_Write_Lock ((HM_Lock *)_l_); \ 00452 } while (0) 00453 #define UNLOCK_LOCK(_l_) do { \ 00454 _H_RW_LOCK_DEBUG_TRACE("HM_Unlock_Lock:",THREAD_ID(),_l_,0); \ 00455 HM_Unlock_Lock ((HM_Lock *)_l_); \ 00456 } while (0) 00457 00458 00459 00460 EXTERNAL void * HM_CDECL HM_Create_Lock (int m); 00461 EXTERNAL void * HM_CDECL HM_Destroy_Lock (HM_Lock * l); 00462 EXTERNAL void HM_CDECL HM_Read_Lock (HM_Lock * l); 00463 EXTERNAL void HM_CDECL HM_Write_Lock (HM_Lock * l); 00464 EXTERNAL void HM_CDECL HM_Unlock_Lock (HM_Lock * l); 00465 00466 00467 #ifdef HMUTEX_IMPLEMENT_FUNCTIONS 00468 00469 GLOBAL_FUNCTION void * HM_CDECL HM_Create_Lock ( 00470 int max_threads) { 00471 HM_Lock * hl; 00472 00473 ALLOCATE_MEMORY (hl, HM_Lock); 00474 memset (hl, 0, sizeof (HM_Lock)); 00475 hl->max_threads = max_threads; 00476 ALLOCATE_MEMORY_ARRAY (hl->threads, max_threads, HM_Per_Thread); 00477 memset (hl->threads, 0, max_threads * sizeof (HM_Per_Thread)); 00478 00479 HM_CONSTRUCT_SEMAPHORE (hl->control, 1, 1); /* "mutex" */ 00480 HM_CONSTRUCT_SEMAPHORE (hl->read, HMUTEX_MAX_CONCURRENT_READERS, 0); 00481 HM_CONSTRUCT_SEMAPHORE (hl->write, 1, 0); 00482 00483 return (void *)hl; 00484 } 00485 00486 GLOBAL_FUNCTION void * HM_CDECL HM_Destroy_Lock ( 00487 HM_Lock * hl) { 00488 00489 HM_DESTRUCT_SEMAPHORE (hl->control); 00490 HM_DESTRUCT_SEMAPHORE (hl->read); 00491 HM_DESTRUCT_SEMAPHORE (hl->write); 00492 00493 FREE_MEMORY_ARRAY (hl->threads, hl->max_threads, HM_Per_Thread); 00494 FREE_MEMORY (hl, HM_Lock); 00495 00496 return 0; 00497 } 00498 00499 00500 #define EXPAND_PER_THREAD_DATA(hl) do { \ 00501 HM_Per_Thread * old_threads = hl->threads; \ 00502 int old_max = hl->max_threads; \ 00503 hl->max_threads *= 2; \ 00504 ALLOCATE_MEMORY_ARRAY (hl->threads, hl->max_threads, HM_Per_Thread); \ 00505 memset (hl->threads, 0, hl->max_threads*sizeof(HM_Per_Thread)); \ 00506 memcpy (hl->threads, old_threads, old_max*sizeof(HM_Per_Thread)); \ 00507 FREE_MEMORY_ARRAY (old_threads, old_max, HM_Per_Thread); \ 00508 } while (0) 00509 00510 00511 GLOBAL_FUNCTION void HM_CDECL HM_Read_Lock ( 00512 HM_Lock * hl) { 00513 HThreadID me = THREAD_ID(); 00514 char const * error = 0; 00515 int mine = 0; 00516 int ii; 00517 00518 HM_WAIT_SEMAPHORE (hl->control); 00519 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Read_Lock: grab control", me, hl, 1); 00520 00521 for (ii=0; ii < hl->active_threads; ii++) { 00522 if (hl->threads[ii].id == me) { /* already have an entry */ 00523 if (hl->threads[ii].state != 0 || /* this thread has a write lock or */ 00524 hl->active_readers > 0) /* it must be a reader */ 00525 mine = 1; /* the thread already has a sufficient lock */ 00526 00527 /* nested read flag is zero -- no change to the state */ 00528 /* but record another nested reference on this thread */ 00529 if (++hl->threads[ii].use_count >= 32) 00530 error = "Read: Nested too deep"; 00531 00532 break; 00533 } 00534 } 00535 00536 if (ii == hl->max_threads) 00537 EXPAND_PER_THREAD_DATA (hl); 00538 00539 if (ii == hl->active_threads) { /* new thread */ 00540 hl->threads[ii].id = me; 00541 hl->threads[ii].use_count = 1; 00542 ++hl->active_threads; 00543 } 00544 if (!mine) { 00545 if (hl->active_writers + hl->pending_writers == 0) { 00546 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Read_Lock: release read", me, hl, 0); 00547 ++hl->active_readers; 00548 HM_RELEASE_SEMAPHORE (hl->read, 1); 00549 } 00550 else 00551 ++hl->pending_readers; 00552 } 00553 00554 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Read_Lock: drop control", me, hl, 1); 00555 HM_RELEASE_SEMAPHORE (hl->control, 1); 00556 00557 if (error) 00558 HMUTEX_ERROR (error); 00559 00560 if (!mine) { 00561 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Read_Lock: wait read", me, hl, 0); 00562 HM_WAIT_SEMAPHORE (hl->read); 00563 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Read_Lock: have read", me, hl, 0); 00564 } 00565 else { 00566 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Read_Lock: mine", me, hl, 0); 00567 } 00568 } 00569 00570 GLOBAL_FUNCTION void HM_CDECL HM_Write_Lock ( 00571 HM_Lock * hl) { 00572 HThreadID me = THREAD_ID(); 00573 char const * error = 0; 00574 int mine = 0; 00575 int ii; 00576 00577 HM_WAIT_SEMAPHORE (hl->control); 00578 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Write_Lock: grab control", me, hl, 1); 00579 00580 for (ii=0; ii < hl->active_threads; ii++) { 00581 if (hl->threads[ii].id == me) { 00582 if (hl->threads[ii].state != 0) { 00583 mine = 1; /* already have a write lock */ 00584 } 00585 else { /* upgrade */ 00586 /* unlock the current read to avoid deadlock */ 00587 if (--hl->active_readers == 0) { 00588 /* and maybe unleash a waiting writer */ 00589 if (hl->pending_writers > 0) { 00590 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Write_Lock: upgrade release write", me, hl, 0); 00591 --hl->pending_writers; 00592 ++hl->active_writers; 00593 HM_RELEASE_SEMAPHORE (hl->write, 1); 00594 } 00595 } 00596 /* will get the thread's write lock below */ 00597 } 00598 /* record the nested write flag */ 00599 hl->threads[ii].state |= 1 << hl->threads[ii].use_count; 00600 /* and record another nested reference on this thread */ 00601 if (++hl->threads[ii].use_count >= 32) 00602 error = "Write: Nested too deep"; 00603 00604 break; 00605 } 00606 } 00607 00608 if (ii == hl->max_threads) 00609 EXPAND_PER_THREAD_DATA (hl); 00610 00611 if (ii == hl->active_threads) { 00612 hl->threads[ii].id = me; 00613 hl->threads[ii].use_count = 1; 00614 hl->threads[ii].state = 1; /* initial write lock */ 00615 ++hl->active_threads; 00616 } 00617 if (!mine) { 00618 if (hl->active_writers + hl->pending_writers + hl->active_readers == 0) { 00619 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Write_Lock: release write", me, hl, 0); 00620 ++hl->active_writers; 00621 HM_RELEASE_SEMAPHORE (hl->write, 1); 00622 } 00623 else 00624 ++hl->pending_writers; 00625 } 00626 00627 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Write_Lock: drop control", me, hl, 1); 00628 HM_RELEASE_SEMAPHORE (hl->control, 1); 00629 00630 if (error) 00631 HMUTEX_ERROR (error); 00632 00633 if (!mine) { 00634 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Write_Lock: wait write", me, hl, 0); 00635 HM_WAIT_SEMAPHORE (hl->write); 00636 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Write_Lock: have write", me, hl, 0); 00637 } 00638 else { 00639 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Write_Lock: mine", me, hl, 0); 00640 } 00641 } 00642 00643 GLOBAL_FUNCTION void HM_CDECL HM_Unlock_Lock ( 00644 HM_Lock * hl) { 00645 HThreadID me = THREAD_ID(); 00646 char const * error = 0; 00647 int reread = 0; 00648 int ii; 00649 int release_reader_limit = 0; 00650 00651 HM_WAIT_SEMAPHORE (hl->control); 00652 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Unlock_Lock: grab control", me, hl, 1); 00653 00654 for (ii=0; ii<hl->max_threads; ii++) { 00655 if (hl->threads[ii].id == me) { 00656 if (--hl->threads[ii].use_count == 0) { /* if this thread done with this lock */ 00657 --hl->active_threads; 00658 00659 /* shift top entry down to fill space */ 00660 if (ii < hl->active_threads) { 00661 hl->threads[ii].id = hl->threads[hl->active_threads].id; 00662 hl->threads[ii].use_count = hl->threads[hl->active_threads].use_count; 00663 hl->threads[ii].state = hl->threads[hl->active_threads].state; 00664 } 00665 /* and clear out unused top entry */ 00666 hl->threads[hl->active_threads].id = 0; 00667 hl->threads[hl->active_threads].use_count = 0; 00668 hl->threads[hl->active_threads].state = 0; 00669 00670 /* now do a "normal" release */ 00671 if (hl->active_writers > 0) { /* should only be "== 1" in any case */ 00672 --hl->active_writers; /* this thread is no longer the writer */ 00673 00674 if (hl->pending_writers > 0) { /* unleash a waiting writer */ 00675 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Unlock_Lock: writer release write", me, hl, 0); 00676 --hl->pending_writers; 00677 ++hl->active_writers; 00678 HM_RELEASE_SEMAPHORE (hl->write, 1); 00679 } 00680 else /* or unleash a bunch of readers */ 00681 release_reader_limit = HMUTEX_MAX_CONCURRENT_READERS; 00682 } 00683 else { 00684 /* if releasing the last active reader, see if we have a writer to unleash */ 00685 if (--hl->active_readers == 0 && hl->pending_writers > 0) { 00686 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Unlock_Lock: reader release write", me, hl, 0); 00687 --hl->pending_writers; 00688 ++hl->active_writers; 00689 HM_RELEASE_SEMAPHORE (hl->write, 1); 00690 } 00691 } 00692 } 00693 else { 00694 int old_state = hl->threads[ii].state; 00695 00696 hl->threads[ii].state &= ~(1 << hl->threads[ii].use_count); 00697 00698 if (old_state != 0 && hl->threads[ii].state == 0) { 00699 /* downgrade - change this thread into a reader */ 00700 --hl->active_writers; 00701 00702 if (hl->pending_writers > 0) { /* unleash a waiting writer */ 00703 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Unlock_Lock: downgrade release write", me, hl, 0); 00704 --hl->pending_writers; 00705 ++hl->active_writers; 00706 ++hl->pending_readers; /* this thread will have to wait now */ 00707 HM_RELEASE_SEMAPHORE (hl->write, 1); 00708 reread = 1; 00709 } 00710 else { 00711 ++hl->active_readers; /* this thread can go ahead */ 00712 00713 /* limited release -- let's share if we can */ 00714 if (hl->pending_writers == 0) 00715 release_reader_limit = HMUTEX_MAX_CONCURRENT_READERS-1; /* less 1 for this thread */ 00716 } 00717 } 00718 } 00719 00720 break; 00721 } 00722 else if (hl->threads[ii].id == 0) { 00723 error = "Unlock: thread not found"; 00724 break; 00725 } 00726 } 00727 00728 /* unleash some waiting readers if we can */ 00729 if (release_reader_limit > 0 && hl->pending_readers > 0) { 00730 int number_to_release = hl->pending_readers; 00731 00732 if (number_to_release > release_reader_limit) 00733 number_to_release = release_reader_limit; 00734 00735 hl->pending_readers -= number_to_release; 00736 hl->active_readers += number_to_release; 00737 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Unlock_Lock: release read", me, number_to_release, 0); /* Note: number, not lock */ 00738 HM_RELEASE_SEMAPHORE (hl->read, number_to_release); 00739 } 00740 00741 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Unlock_Lock: drop control", me, hl, 1); 00742 HM_RELEASE_SEMAPHORE (hl->control, 1); 00743 00744 if (error) 00745 HMUTEX_ERROR (error); 00746 00747 if (reread) { 00748 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Unlock_Lock: wait read", me, hl, 0); 00749 HM_WAIT_SEMAPHORE (hl->read); 00750 _H_RW_LOCK_DEBUG_TRACE_INTERNAL("HM_Unlock_Lock: have read", me, hl, 0); 00751 } 00752 } 00753 00754 00755 #endif /* ifdef HMUTEX_IMPLEMENT_FUNCTIONS */ 00756 00757 #endif /* ifndef DISABLE_MUTEX */ 00758 00759 #endif /* HOOPS_MUTEX_DEFINED */