| | 32 | typedef struct private_rwlock_t private_rwlock_t; |
|---|
| | 33 | |
|---|
| | 34 | #ifdef LOCK_PROFILER |
|---|
| | 35 | |
|---|
| | 36 | /** |
|---|
| | 37 | * Do not report mutexes with an overall waiting time smaller than this (in us) |
|---|
| | 38 | */ |
|---|
| | 39 | #define PROFILE_TRESHHOLD 1000 |
|---|
| | 40 | |
|---|
| | 41 | #include <utils/backtrace.h> |
|---|
| | 42 | |
|---|
| | 43 | typedef struct lock_profile_t lock_profile_t; |
|---|
| | 44 | |
|---|
| | 45 | struct lock_profile_t { |
|---|
| | 46 | |
|---|
| | 47 | /** |
|---|
| | 48 | * how long threads have waited for the lock in this mutex so far |
|---|
| | 49 | */ |
|---|
| | 50 | struct timeval waited; |
|---|
| | 51 | |
|---|
| | 52 | /** |
|---|
| | 53 | * backtrace where mutex has been created |
|---|
| | 54 | */ |
|---|
| | 55 | backtrace_t *backtrace; |
|---|
| | 56 | }; |
|---|
| | 57 | |
|---|
| | 58 | /** |
|---|
| | 59 | * Print and cleanup mutex profiler |
|---|
| | 60 | */ |
|---|
| | 61 | static void profiler_cleanup(lock_profile_t *profile) |
|---|
| | 62 | { |
|---|
| | 63 | if (profile->waited.tv_sec > 0 || |
|---|
| | 64 | profile->waited.tv_usec > PROFILE_TRESHHOLD) |
|---|
| | 65 | { |
|---|
| | 66 | fprintf(stderr, "%d.%06ds in lock created at:", |
|---|
| | 67 | profile->waited.tv_sec, profile->waited.tv_usec); |
|---|
| | 68 | profile->backtrace->log(profile->backtrace, stderr); |
|---|
| | 69 | } |
|---|
| | 70 | profile->backtrace->destroy(profile->backtrace); |
|---|
| | 71 | } |
|---|
| | 72 | |
|---|
| | 73 | /** |
|---|
| | 74 | * Initialize mutex profiler |
|---|
| | 75 | */ |
|---|
| | 76 | static void profiler_init(lock_profile_t *profile) |
|---|
| | 77 | { |
|---|
| | 78 | profile->backtrace = backtrace_create(3); |
|---|
| | 79 | timerclear(&profile->waited); |
|---|
| | 80 | } |
|---|
| | 81 | |
|---|
| | 82 | #define profiler_start(profile) { \ |
|---|
| | 83 | struct timeval _start, _end, _diff; \ |
|---|
| | 84 | gettimeofday(&_start, NULL); |
|---|
| | 85 | |
|---|
| | 86 | #define profiler_end(profile) \ |
|---|
| | 87 | gettimeofday(&_end, NULL); \ |
|---|
| | 88 | timersub(&_end, &_start, &_diff); \ |
|---|
| | 89 | timeradd(&(profile)->waited, &_diff, &(profile)->waited); } |
|---|
| | 90 | |
|---|
| | 91 | #else /* !LOCK_PROFILER */ |
|---|
| | 92 | |
|---|
| | 93 | #define lock_profile_t struct {} |
|---|
| | 94 | #define profiler_cleanup(...) {} |
|---|
| | 95 | #define profiler_init(...) {} |
|---|
| | 96 | #define profiler_start(...) {} |
|---|
| | 97 | #define profiler_end(...) {} |
|---|
| | 98 | |
|---|
| | 99 | #endif /* LOCK_PROFILER */ |
|---|
| 109 | | #ifdef LOCK_PROFILER |
|---|
| 110 | | /** |
|---|
| 111 | | * Print and cleanup mutex profiler |
|---|
| 112 | | */ |
|---|
| 113 | | static void profiler_cleanup(private_mutex_t *this) |
|---|
| 114 | | { |
|---|
| 115 | | if (this->waited.tv_sec > 0 || |
|---|
| 116 | | this->waited.tv_usec > PROFILE_TRESHHOLD) |
|---|
| 117 | | { |
|---|
| 118 | | fprintf(stderr, "waited %d.%06ds in mutex, created at:", |
|---|
| 119 | | this->waited.tv_sec, this->waited.tv_usec); |
|---|
| 120 | | this->backtrace->log(this->backtrace, stderr); |
|---|
| 121 | | } |
|---|
| 122 | | this->backtrace->destroy(this->backtrace); |
|---|
| 123 | | } |
|---|
| 124 | | |
|---|
| 125 | | /** |
|---|
| 126 | | * Initialize mutex profiler |
|---|
| 127 | | */ |
|---|
| 128 | | static void profiler_init(private_mutex_t *this) |
|---|
| 129 | | { |
|---|
| 130 | | this->backtrace = backtrace_create(3); |
|---|
| 131 | | timerclear(&this->waited); |
|---|
| 132 | | } |
|---|
| | 164 | /** |
|---|
| | 165 | * private data of rwlock |
|---|
| | 166 | */ |
|---|
| | 167 | struct private_rwlock_t { |
|---|
| | 168 | |
|---|
| | 169 | /** |
|---|
| | 170 | * public functions |
|---|
| | 171 | */ |
|---|
| | 172 | rwlock_t public; |
|---|
| | 173 | |
|---|
| | 174 | /** |
|---|
| | 175 | * wrapped pthread rwlock |
|---|
| | 176 | */ |
|---|
| | 177 | pthread_rwlock_t rwlock; |
|---|
| | 178 | |
|---|
| | 179 | /** |
|---|
| | 180 | * profiling info, if enabled |
|---|
| | 181 | */ |
|---|
| | 182 | lock_profile_t profile; |
|---|
| | 183 | }; |
|---|
| 146 | | gettimeofday(&end, NULL); |
|---|
| 147 | | |
|---|
| 148 | | timersub(&end, &start, &diff); |
|---|
| 149 | | timeradd(&this->waited, &diff, &this->waited); |
|---|
| 150 | | } |
|---|
| 151 | | #else /* !LOCK_PROFILER */ |
|---|
| 152 | | |
|---|
| 153 | | /** dummy implementations */ |
|---|
| 154 | | static void profiler_cleanup(private_mutex_t *this) {} |
|---|
| 155 | | static void profiler_init(private_mutex_t *this) {} |
|---|
| 156 | | |
|---|
| 157 | | /** |
|---|
| 158 | | * Implementation of mutex_t.lock. |
|---|
| 159 | | */ |
|---|
| 160 | | static void lock(private_mutex_t *this) |
|---|
| 161 | | { |
|---|
| 162 | | if (pthread_mutex_lock(&this->mutex)) |
|---|
| 163 | | { |
|---|
| 164 | | DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", ""); |
|---|
| 165 | | } |
|---|
| 166 | | } |
|---|
| 167 | | #endif /* LOCK_PROFILER */ |
|---|
| | 195 | profiler_end(&this->profile); |
|---|
| | 196 | } |
|---|
| | 423 | /** |
|---|
| | 424 | * Implementation of rwlock_t.read_lock |
|---|
| | 425 | */ |
|---|
| | 426 | static void read_lock(private_rwlock_t *this) |
|---|
| | 427 | { |
|---|
| | 428 | profiler_start(&this->profile); |
|---|
| | 429 | pthread_rwlock_rdlock(&this->rwlock); |
|---|
| | 430 | profiler_end(&this->profile); |
|---|
| | 431 | } |
|---|
| | 432 | |
|---|
| | 433 | /** |
|---|
| | 434 | * Implementation of rwlock_t.write_lock |
|---|
| | 435 | */ |
|---|
| | 436 | static void write_lock(private_rwlock_t *this) |
|---|
| | 437 | { |
|---|
| | 438 | profiler_start(&this->profile); |
|---|
| | 439 | pthread_rwlock_wrlock(&this->rwlock); |
|---|
| | 440 | profiler_end(&this->profile); |
|---|
| | 441 | } |
|---|
| | 442 | |
|---|
| | 443 | /** |
|---|
| | 444 | * Implementation of rwlock_t.unlock |
|---|
| | 445 | */ |
|---|
| | 446 | static void rw_unlock(private_rwlock_t *this) |
|---|
| | 447 | { |
|---|
| | 448 | pthread_rwlock_unlock(&this->rwlock); |
|---|
| | 449 | } |
|---|
| | 450 | |
|---|
| | 451 | /** |
|---|
| | 452 | * Implementation of rwlock_t.destroy |
|---|
| | 453 | */ |
|---|
| | 454 | static void rw_destroy(private_rwlock_t *this) |
|---|
| | 455 | { |
|---|
| | 456 | pthread_rwlock_destroy(&this->rwlock); |
|---|
| | 457 | profiler_cleanup(&this->profile); |
|---|
| | 458 | free(this); |
|---|
| | 459 | } |
|---|
| | 460 | |
|---|
| | 461 | /* |
|---|
| | 462 | * see header file |
|---|
| | 463 | */ |
|---|
| | 464 | rwlock_t *rwlock_create(rwlock_type_t type) |
|---|
| | 465 | { |
|---|
| | 466 | switch (type) |
|---|
| | 467 | { |
|---|
| | 468 | case RWLOCK_DEFAULT: |
|---|
| | 469 | default: |
|---|
| | 470 | { |
|---|
| | 471 | private_rwlock_t *this = malloc_thing(private_rwlock_t); |
|---|
| | 472 | |
|---|
| | 473 | this->public.read_lock = (void(*)(rwlock_t*))read_lock; |
|---|
| | 474 | this->public.write_lock = (void(*)(rwlock_t*))write_lock; |
|---|
| | 475 | this->public.unlock = (void(*)(rwlock_t*))rw_unlock; |
|---|
| | 476 | this->public.destroy = (void(*)(rwlock_t*))rw_destroy; |
|---|
| | 477 | |
|---|
| | 478 | pthread_rwlock_init(&this->rwlock, NULL); |
|---|
| | 479 | profiler_init(&this->profile); |
|---|
| | 480 | |
|---|
| | 481 | return &this->public; |
|---|
| | 482 | } |
|---|
| | 483 | } |
|---|
| | 484 | } |
|---|
| | 485 | |
|---|