HOOPS/3dGS I.M. Interface

     << Back      Full Index      Forward >>


hmutex.h

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 */
Main Index
HOOPS/3dGS I.M. Interface

     << Back      Full Index      Forward >>