]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
7c673cae FG |
14 | |
15 | #include "common/Mutex.h" | |
16 | #include "common/perf_counters.h" | |
7c673cae | 17 | #include "common/config.h" |
7c673cae FG |
18 | #include "common/Clock.h" |
19 | #include "common/valgrind.h" | |
20 | ||
21 | Mutex::Mutex(const std::string &n, bool r, bool ld, | |
22 | bool bt, | |
23 | CephContext *cct) : | |
24 | name(n), id(-1), recursive(r), lockdep(ld), backtrace(bt), nlock(0), | |
25 | locked_by(0), cct(cct), logger(0) | |
26 | { | |
27 | ANNOTATE_BENIGN_RACE_SIZED(&id, sizeof(id), "Mutex lockdep id"); | |
28 | ANNOTATE_BENIGN_RACE_SIZED(&nlock, sizeof(nlock), "Mutex nlock"); | |
29 | ANNOTATE_BENIGN_RACE_SIZED(&locked_by, sizeof(locked_by), "Mutex locked_by"); | |
30 | if (cct) { | |
31 | PerfCountersBuilder b(cct, string("mutex-") + name, | |
32 | l_mutex_first, l_mutex_last); | |
33 | b.add_time_avg(l_mutex_wait, "wait", "Average time of mutex in locked state"); | |
34 | logger = b.create_perf_counters(); | |
35 | cct->get_perfcounters_collection()->add(logger); | |
36 | logger->set(l_mutex_wait, 0); | |
37 | } | |
38 | if (recursive) { | |
39 | // Mutexes of type PTHREAD_MUTEX_RECURSIVE do all the same checks as | |
40 | // mutexes of type PTHREAD_MUTEX_ERRORCHECK. | |
41 | pthread_mutexattr_t attr; | |
42 | pthread_mutexattr_init(&attr); | |
43 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); | |
44 | pthread_mutex_init(&_m,&attr); | |
45 | pthread_mutexattr_destroy(&attr); | |
46 | if (lockdep && g_lockdep) | |
47 | _register(); | |
48 | } | |
49 | else if (lockdep) { | |
50 | // If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then error checking | |
51 | // shall be provided. If a thread attempts to relock a mutex that it | |
52 | // has already locked, an error shall be returned. If a thread | |
53 | // attempts to unlock a mutex that it has not locked or a mutex which | |
54 | // is unlocked, an error shall be returned. | |
55 | pthread_mutexattr_t attr; | |
56 | pthread_mutexattr_init(&attr); | |
57 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); | |
58 | pthread_mutex_init(&_m, &attr); | |
59 | pthread_mutexattr_destroy(&attr); | |
60 | if (g_lockdep) | |
61 | _register(); | |
62 | } | |
63 | else { | |
224ce89b WB |
64 | // If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively |
65 | // lock the mutex results in undefined behavior. Attempting to unlock the | |
66 | // mutex if it was not locked by the calling thread results in undefined | |
67 | // behavior. Attempting to unlock the mutex if it is not locked results in | |
68 | // undefined behavior. | |
7c673cae FG |
69 | pthread_mutex_init(&_m, NULL); |
70 | } | |
71 | } | |
72 | ||
73 | Mutex::~Mutex() { | |
74 | assert(nlock == 0); | |
75 | ||
76 | // helgrind gets confused by condition wakeups leading to mutex destruction | |
77 | ANNOTATE_BENIGN_RACE_SIZED(&_m, sizeof(_m), "Mutex primitive"); | |
78 | pthread_mutex_destroy(&_m); | |
79 | ||
80 | if (cct && logger) { | |
81 | cct->get_perfcounters_collection()->remove(logger); | |
82 | delete logger; | |
83 | } | |
84 | if (lockdep && g_lockdep) { | |
85 | lockdep_unregister(id); | |
86 | } | |
87 | } | |
88 | ||
89 | void Mutex::Lock(bool no_lockdep) { | |
90 | int r; | |
91 | ||
92 | if (lockdep && g_lockdep && !no_lockdep && !recursive) _will_lock(); | |
93 | ||
94 | if (logger && cct && cct->_conf->mutex_perf_counter) { | |
95 | utime_t start; | |
96 | // instrumented mutex enabled | |
97 | start = ceph_clock_now(); | |
98 | if (TryLock()) { | |
99 | goto out; | |
100 | } | |
101 | ||
102 | r = pthread_mutex_lock(&_m); | |
103 | ||
104 | logger->tinc(l_mutex_wait, | |
105 | ceph_clock_now() - start); | |
106 | } else { | |
107 | r = pthread_mutex_lock(&_m); | |
108 | } | |
109 | ||
110 | assert(r == 0); | |
111 | if (lockdep && g_lockdep) _locked(); | |
112 | _post_lock(); | |
113 | ||
114 | out: | |
115 | ; | |
116 | } | |
117 | ||
118 | void Mutex::Unlock() { | |
119 | _pre_unlock(); | |
120 | if (lockdep && g_lockdep) _will_unlock(); | |
121 | int r = pthread_mutex_unlock(&_m); | |
122 | assert(r == 0); | |
123 | } |