00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "ReadersWritersLock.H"
00026 #include "Basics.H"
00027 #include "lock_timing.H"
00028
00029 #include <assert.h>
00030 #include <sys/types.h>
00031 #include <unistd.h>
00032
00033 #ifndef USE_PTHREAD_RWLOCK
00034 struct RWLock_Queue_Item
00035 {
00036
00037 RWLock_Queue_Item *next, *prev;
00038
00039
00040 bool writer;
00041
00042
00043 unsigned int waiting_count;
00044
00045
00046 Basics::cond my_turn;
00047
00048 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00049
00050
00051
00052 time_t enqueue_time;
00053 pthread_t enqueue_thread;
00054 #endif
00055
00056 RWLock_Queue_Item(bool write, RWLock_Queue_Item *&tail)
00057 : writer(write), waiting_count(0),
00058 next(0), prev(tail)
00059 {
00060
00061 tail = this;
00062
00063
00064 if(prev)
00065 {
00066 assert(prev->next == 0);
00067 prev->next = this;
00068 }
00069
00070 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00071
00072
00073 enqueue_time = time(NULL);
00074 enqueue_thread = pthread_self();
00075 #endif
00076 }
00077
00078 ~RWLock_Queue_Item()
00079 {
00080
00081
00082 assert(prev == 0);
00083
00084
00085 if(next)
00086 {
00087 assert(next->prev == this);
00088 next->prev = 0;
00089 }
00090 }
00091 };
00092 #endif
00093
00094 ReadersWritersLock::~ReadersWritersLock() throw()
00095 {
00096 #ifdef USE_PTHREAD_RWLOCK
00097
00098 while(1)
00099 {
00100
00101 int result = pthread_rwlock_destroy(&rwlock);
00102
00103 if(result == 0) break;
00104
00105
00106 assert(result == EBUSY);
00107
00108
00109 result = pthread_rwlock_wrlock(&rwlock);
00110 assert(result == 0);
00111
00112
00113 result = pthread_rwlock_unlock(&rwlock);
00114 assert(result == 0);
00115 }
00116 #else
00117
00118
00119 while(1)
00120 {
00121
00122 acquireWrite();
00123
00124 mu.lock();
00125 bool waiters = (q_head != 0);
00126 mu.unlock();
00127 if(waiters)
00128 {
00129
00130
00131 releaseWrite();
00132 }
00133 else
00134 {
00135
00136
00137 break;
00138 }
00139 }
00140 #endif
00141 }
00142
00143 ReadersWritersLock::ReadersWritersLock(bool favorWriters) throw()
00144 {
00145 #ifdef USE_PTHREAD_RWLOCK
00146 write_locked = false;
00147 while(1)
00148 {
00149 int result = pthread_rwlock_init(&rwlock, NULL);
00150
00151 if(result == 0) break;
00152
00153 assert(result == EAGAIN);
00154 }
00155 #else
00156 readers = 0;
00157 writers = 0;
00158
00159 q_head = 0;
00160 q_tail = 0;
00161
00162 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00163 acquire_time = 0;
00164 acquire_thread = 0;
00165 #endif
00166
00167 #endif
00168 }
00169
00170 void ReadersWritersLock::acquireRead() throw()
00171 {
00172 RWLOCK_ACQUIRE_READ_START(this);
00173 #ifdef USE_PTHREAD_RWLOCK
00174 while(1)
00175 {
00176 int result = pthread_rwlock_rdlock(&rwlock);
00177
00178 if(result == 0) break;
00179
00180 assert(result == EAGAIN);
00181 }
00182 #else
00183 mu.lock();
00184
00185 if((writers > 0) ||
00186
00187 ((q_head != 0) &&
00188
00189
00190
00191
00192 !((q_head == q_tail) && !q_head->writer)))
00193
00194 {
00195 RWLock_Queue_Item *q_entry = 0;
00196
00197
00198
00199 if((q_tail != 0) && (!q_tail->writer))
00200 {
00201 assert(q_head != 0);
00202 q_entry = q_tail;
00203
00204 }
00205
00206
00207 else
00208 {
00209 q_entry = NEW_CONSTR(RWLock_Queue_Item, (false, this->q_tail));
00210
00211
00212 if(q_head == 0)
00213 {
00214 assert(q_tail->prev == 0);
00215 q_head = q_entry;
00216 }
00217
00218
00219
00220 assert(((q_head != 0) && (q_tail != 0)) ||
00221 ((q_head == 0) && (q_tail == 0)));
00222 }
00223
00224 assert(q_entry != 0);
00225
00226 q_entry->waiting_count++;
00227 q_entry->my_turn.wait(this->mu);
00228 q_entry->waiting_count--;
00229
00230
00231
00232 assert(q_entry == q_head);
00233 assert(writers == 0);
00234
00235
00236 if(q_entry->waiting_count == 0)
00237 {
00238 q_head = q_head->next;
00239
00240
00241
00242 if(q_tail == q_entry)
00243 {
00244 assert(q_head == 0);
00245 q_tail = 0;
00246 }
00247
00248
00249
00250 assert(((q_head != 0) && (q_tail != 0)) ||
00251 ((q_head == 0) && (q_tail == 0)));
00252
00253
00254 delete q_entry;
00255 }
00256 }
00257
00258
00259 readers++;
00260
00261 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00262 if(readers == 1)
00263 {
00264
00265 acquire_time = time(NULL);
00266 acquire_thread = pthread_self();
00267 }
00268 #endif
00269
00270 mu.unlock();
00271 #endif
00272 RWLOCK_ACQUIRE_READ_DONE(this, false);
00273 }
00274
00275 void ReadersWritersLock::releaseRead() throw()
00276 {
00277 RWLOCK_RELEASE_START(this);
00278 #ifdef USE_PTHREAD_RWLOCK
00279 int result = pthread_rwlock_unlock(&rwlock);
00280
00281 assert(result == 0);
00282 #else
00283 mu.lock();
00284
00285
00286 assert(readers > 0);
00287 readers--;
00288
00289 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00290 if(readers == 0)
00291 {
00292
00293 acquire_time = 0;
00294 acquire_thread = 0;
00295 }
00296 #endif
00297
00298
00299
00300 if((readers == 0) && (q_head != 0))
00301 {
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 q_head->my_turn.broadcast();
00313 }
00314 mu.unlock();
00315 #endif
00316 RWLOCK_RELEASE_DONE(this);
00317 }
00318
00319 void ReadersWritersLock::acquireWrite() throw()
00320 {
00321 RWLOCK_ACQUIRE_WRITE_START(this);
00322 #ifdef USE_PTHREAD_RWLOCK
00323 while(1)
00324 {
00325 int result = pthread_rwlock_wrlock(&rwlock);
00326
00327 if(result == 0) break;
00328
00329 assert(result == EAGAIN);
00330 }
00331 write_locked = true;
00332 #else
00333 mu.lock();
00334
00335
00336
00337 if((readers > 0) || (writers > 0) || (q_head != 0))
00338 {
00339
00340
00341 RWLock_Queue_Item q_entry(true, this->q_tail);
00342
00343
00344 if(q_head == 0)
00345 {
00346 assert(q_tail->prev == 0);
00347 q_head = &q_entry;
00348 }
00349
00350
00351
00352 assert(((q_head != 0) && (q_tail != 0)) ||
00353 ((q_head == 0) && (q_tail == 0)));
00354
00355
00356 q_entry.my_turn.wait(this->mu);
00357
00358
00359
00360 assert(&q_entry == q_head);
00361 assert((writers == 0) && (readers == 0));
00362
00363
00364 q_head = q_head->next;
00365
00366
00367
00368 if(q_tail == &q_entry)
00369 {
00370 assert(q_head == 0);
00371 q_tail = 0;
00372 }
00373
00374
00375
00376 assert(((q_head != 0) && (q_tail != 0)) ||
00377 ((q_head == 0) && (q_tail == 0)));
00378 }
00379 writers++;
00380
00381 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00382
00383 acquire_time = time(NULL);
00384 acquire_thread = pthread_self();
00385 #endif
00386
00387 mu.unlock();
00388 #endif
00389 RWLOCK_ACQUIRE_WRITE_DONE(this, false);
00390 }
00391
00392 void ReadersWritersLock::releaseWrite() throw()
00393 {
00394 RWLOCK_RELEASE_START(this);
00395 #ifdef USE_PTHREAD_RWLOCK
00396 assert(write_locked);
00397 write_locked = false;
00398 int result = pthread_rwlock_unlock(&rwlock);
00399
00400 assert(result == 0);
00401 #else
00402 mu.lock();
00403 assert(writers == 1);
00404 writers = 0;
00405
00406 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00407
00408 acquire_time = 0;
00409 acquire_thread = 0;
00410 #endif
00411
00412
00413 if(q_head != 0)
00414 {
00415
00416
00417
00418 q_head->my_turn.broadcast();
00419 }
00420 mu.unlock();
00421 #endif
00422 RWLOCK_RELEASE_DONE(this);
00423 }
00424
00425 bool ReadersWritersLock::tryRead() throw()
00426 {
00427 RWLOCK_ACQUIRE_READ_START(this);
00428 bool gotit;
00429 #ifdef USE_PTHREAD_RWLOCK
00430 int result = pthread_rwlock_tryrdlock(&rwlock);
00431 gotit = (result == 0);
00432 #else
00433 mu.lock();
00434
00435
00436
00437 if((writers > 0) || (q_head != 0)) {
00438 gotit = false;
00439 } else {
00440 gotit = true;
00441 readers++;
00442
00443 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00444 if(readers == 1)
00445 {
00446
00447 acquire_time = time(NULL);
00448 acquire_thread = pthread_self();
00449 }
00450 #endif
00451 }
00452 mu.unlock();
00453 #endif
00454 RWLOCK_ACQUIRE_READ_DONE(this, !gotit);
00455 return gotit;
00456 }
00457
00458 bool ReadersWritersLock::tryWrite() throw()
00459 {
00460 bool gotit;
00461 RWLOCK_ACQUIRE_WRITE_START(this);
00462 #ifdef USE_PTHREAD_RWLOCK
00463 int result = pthread_rwlock_trywrlock(&rwlock);
00464 if(result == 0) write_locked = true;
00465 gotit = (result == 0);
00466 #else
00467 mu.lock();
00468
00469
00470 if ((readers > 0) || (writers > 0) || (q_head != 0)) {
00471 gotit = false;
00472 } else {
00473 gotit = true;
00474 writers++;
00475 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00476
00477 acquire_time = time(NULL);
00478 acquire_thread = pthread_self();
00479 #endif
00480 }
00481 mu.unlock();
00482 #endif
00483 RWLOCK_ACQUIRE_WRITE_DONE(this, !gotit);
00484 return gotit;
00485 }
00486
00487 bool ReadersWritersLock::release() throw()
00488 {
00489 RWLOCK_RELEASE_START(this);
00490 bool hadwrite;
00491 #ifdef USE_PTHREAD_RWLOCK
00492 hadwrite = write_locked;
00493 if(write_locked) write_locked = false;
00494 int result = pthread_rwlock_unlock(&rwlock);
00495
00496 assert(result == 0);
00497 #else
00498 mu.lock();
00499 hadwrite = writers > 0;
00500 if (hadwrite) {
00501 assert(writers == 1);
00502 writers = 0;
00503 } else {
00504 assert(readers > 0);
00505 readers--;
00506 }
00507
00508 #if !defined(NO_ACQUIRE_DEBUG_DATA)
00509 if(hadwrite || (readers == 0))
00510 {
00511
00512
00513 acquire_time = 0;
00514 acquire_thread = 0;
00515 }
00516 #endif
00517
00518
00519
00520
00521 if((q_head != 0) &&
00522 (hadwrite || (readers == 0) || !q_head->writer))
00523 {
00524
00525
00526
00527 q_head->my_turn.broadcast();
00528 }
00529
00530 mu.unlock();
00531 #endif
00532 RWLOCK_RELEASE_DONE(this);
00533 return hadwrite;
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605