Mutex.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. EQ2Emulator: Everquest II Server Emulator
  3. Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
  4. This file is part of EQ2Emulator.
  5. EQ2Emulator is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. EQ2Emulator is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "../common/Log.h"
  17. #include "../common/debug.h"
  18. #include "../common/Mutex.h"
  19. Mutex::Mutex() {
  20. readers = 0;
  21. mlocked = false;
  22. writing = false;
  23. name = "";
  24. #ifdef DEBUG
  25. stack.clear();
  26. #endif
  27. //CSLock is a pointer so we can use a different attribute type on create
  28. CSLock = new CriticalSection(MUTEX_ATTRIBUTE_RECURSIVE);
  29. }
  30. Mutex::~Mutex() {
  31. safe_delete(CSLock);
  32. #ifdef DEBUG
  33. stack.clear();
  34. #endif
  35. }
  36. void Mutex::SetName(string in_name) {
  37. #ifdef DEBUG
  38. name = in_name;
  39. #endif
  40. }
  41. void Mutex::lock() {
  42. #ifdef DEBUG
  43. int i = 0;
  44. #endif
  45. if (name.length() > 0) {
  46. while (mlocked) {
  47. #ifdef DEBUG
  48. if (i > MUTEX_TIMEOUT_MILLISECONDS) {
  49. LogWrite(MUTEX__ERROR, 0, "Mutex", "Possible deadlock attempt by '%s'!", name.c_str());
  50. return;
  51. }
  52. i++;
  53. #endif
  54. Sleep(1);
  55. }
  56. }
  57. mlocked = true;
  58. CSLock->lock();
  59. }
  60. bool Mutex::trylock() {
  61. return CSLock->trylock();
  62. }
  63. void Mutex::unlock() {
  64. CSLock->unlock();
  65. mlocked = false;
  66. }
  67. void Mutex::readlock(const char* function, int32 line) {
  68. #ifdef DEBUG
  69. int32 i = 0;
  70. #endif
  71. while (true) {
  72. //Loop until there isn't a writer, then we can read!
  73. CSRead.lock();
  74. if (!writing) {
  75. readers++;
  76. CSRead.unlock();
  77. #ifdef DEBUG
  78. CSStack.lock();
  79. if (function)
  80. stack[(string)function]++;
  81. CSStack.unlock();
  82. #endif
  83. return;
  84. }
  85. CSRead.unlock();
  86. #ifdef DEBUG
  87. if (i > MUTEX_TIMEOUT_MILLISECONDS) {
  88. LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out waiting for a readlock!", name.c_str(), function ? function : "name_not_provided", line);
  89. LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
  90. map<string, int32>::iterator itr;
  91. CSStack.lock();
  92. for (itr = stack.begin(); itr != stack.end(); itr++) {
  93. if (itr->second > 0 && itr->first.length() > 0)
  94. LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
  95. }
  96. CSStack.unlock();
  97. i = 0;
  98. continue;
  99. }
  100. i++;
  101. #endif
  102. Sleep(1);
  103. }
  104. }
  105. void Mutex::releasereadlock(const char* function, int32 line) {
  106. //Wait for the readcount lock
  107. CSRead.lock();
  108. //Lower the readcount by one, when readcount is 0 writers may start writing
  109. readers--;
  110. CSRead.unlock();
  111. #ifdef DEBUG
  112. CSStack.lock();
  113. if (function) {
  114. map<string, int32>::iterator itr = stack.find((string)function);
  115. if (itr != stack.end()) {
  116. if (--(itr->second) == 0) {
  117. stack.erase(itr);
  118. }
  119. }
  120. }
  121. CSStack.unlock();
  122. #endif
  123. }
  124. bool Mutex::tryreadlock(const char* function) {
  125. //This returns true if able to instantly obtain a readlock, false if not
  126. CSRead.lock();
  127. if (!writing) {
  128. readers++;
  129. CSRead.unlock();
  130. }
  131. else {
  132. CSRead.unlock();
  133. return false;
  134. }
  135. #ifdef DEBUG
  136. CSStack.lock();
  137. if (function)
  138. stack[(string)function]++;
  139. CSStack.unlock();
  140. #endif
  141. return true;
  142. }
  143. void Mutex::writelock(const char* function, int32 line) {
  144. //Wait until the writer lock becomes available, then we can be the only writer!
  145. #ifdef DEBUG
  146. int32 i = 0;
  147. #endif
  148. while (!CSWrite.trylock()) {
  149. #ifdef DEBUG
  150. if (i > MUTEX_TIMEOUT_MILLISECONDS) {
  151. LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out waiting on another writelock!", name.c_str(), function ? function : "name_not_provided", line);
  152. LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
  153. map<string, int32>::iterator itr;
  154. CSStack.lock();
  155. for (itr = stack.begin(); itr != stack.end(); itr++) {
  156. if (itr->second > 0 && itr->first.length() > 0)
  157. LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
  158. }
  159. CSStack.unlock();
  160. i = 0;
  161. continue;
  162. }
  163. i++;
  164. #endif
  165. Sleep(1);
  166. }
  167. waitReaders(function, line);
  168. #ifdef DEBUG
  169. CSStack.lock();
  170. if (function)
  171. stack[(string)function]++;
  172. CSStack.unlock();
  173. #endif
  174. }
  175. void Mutex::releasewritelock(const char* function, int32 line) {
  176. //Wait for the readcount lock
  177. CSRead.lock();
  178. //Readers are aloud again
  179. writing = false;
  180. CSRead.unlock();
  181. //Allow other writers to write
  182. CSWrite.unlock();
  183. #ifdef DEBUG
  184. CSStack.lock();
  185. if (function) {
  186. map<string, int32>::iterator itr = stack.find((string)function);
  187. if (itr != stack.end()) {
  188. if (--(itr->second) == 0) {
  189. stack.erase(itr);
  190. }
  191. }
  192. }
  193. CSStack.unlock();
  194. #endif
  195. }
  196. bool Mutex::trywritelock(const char* function) {
  197. //This returns true if able to instantly obtain a writelock, false if not
  198. if (CSWrite.trylock()) {
  199. CSRead.lock();
  200. if (readers == 0)
  201. writing = true;
  202. CSRead.unlock();
  203. if (!writing) {
  204. CSWrite.unlock();
  205. return false;
  206. }
  207. }
  208. else
  209. return false;
  210. #ifdef DEBUG
  211. CSStack.lock();
  212. if (function)
  213. stack[(string)function]++;
  214. CSStack.unlock();
  215. #endif
  216. return true;
  217. }
  218. void Mutex::waitReaders(const char* function, int32 line)
  219. {
  220. //Wait for all current readers to stop, then we can write!
  221. #ifdef DEBUG
  222. int32 i = 0;
  223. #endif
  224. while (true)
  225. {
  226. CSRead.lock();
  227. if (readers == 0)
  228. {
  229. writing = true;
  230. CSRead.unlock();
  231. break;
  232. }
  233. CSRead.unlock();
  234. #ifdef DEBUG
  235. if (i > MUTEX_TIMEOUT_MILLISECONDS) {
  236. LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out while waiting on readers!", name.c_str(), function ? function : "name_not_provided", line);
  237. LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
  238. map<string, int32>::iterator itr;
  239. CSStack.lock();
  240. for (itr = stack.begin(); itr != stack.end(); itr++) {
  241. if (itr->second > 0 && itr->first.length() > 0)
  242. LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
  243. }
  244. CSStack.unlock();
  245. i = 0;
  246. continue;
  247. }
  248. i++;
  249. #endif
  250. Sleep(1);
  251. }
  252. }
  253. LockMutex::LockMutex(Mutex* in_mut, bool iLock) {
  254. mut = in_mut;
  255. locked = iLock;
  256. if (locked) {
  257. mut->lock();
  258. }
  259. }
  260. LockMutex::~LockMutex() {
  261. if (locked) {
  262. mut->unlock();
  263. }
  264. }
  265. void LockMutex::unlock() {
  266. if (locked)
  267. mut->unlock();
  268. locked = false;
  269. }
  270. void LockMutex::lock() {
  271. if (!locked)
  272. mut->lock();
  273. locked = true;
  274. }
  275. CriticalSection::CriticalSection(int attribute) {
  276. #ifdef WIN32
  277. InitializeCriticalSection(&CSMutex);
  278. #else
  279. pthread_mutexattr_init(&type_attribute);
  280. switch (attribute)
  281. {
  282. case MUTEX_ATTRIBUTE_FAST:
  283. pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_FAST_NP);
  284. break;
  285. case MUTEX_ATTRIBUTE_RECURSIVE:
  286. pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_RECURSIVE_NP);
  287. break;
  288. case MUTEX_ATTRIBUTE_ERRORCHK:
  289. pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_ERRORCHECK_NP);
  290. break;
  291. default:
  292. LogWrite(MUTEX__DEBUG, 0, "Critical Section", "Invalid mutex attribute type! Using PTHREAD_MUTEX_FAST_NP");
  293. pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_FAST_NP);
  294. break;
  295. }
  296. pthread_mutex_init(&CSMutex, &type_attribute);
  297. #endif
  298. }
  299. CriticalSection::~CriticalSection() {
  300. #ifdef WIN32
  301. DeleteCriticalSection(&CSMutex);
  302. #else
  303. pthread_mutex_destroy(&CSMutex);
  304. pthread_mutexattr_destroy(&type_attribute);
  305. #endif
  306. }
  307. void CriticalSection::lock() {
  308. //Waits for a lock on this critical section
  309. #ifdef WIN32
  310. EnterCriticalSection(&CSMutex);
  311. #else
  312. pthread_mutex_lock(&CSMutex);
  313. #endif
  314. }
  315. void CriticalSection::unlock() {
  316. //Gets rid of one of the current thread's locks on this critical section
  317. #ifdef WIN32
  318. LeaveCriticalSection(&CSMutex);
  319. #else
  320. pthread_mutex_unlock(&CSMutex);
  321. #endif
  322. }
  323. bool CriticalSection::trylock() {
  324. //Returns true if able to instantly get a lock on this critical section, false if not
  325. #ifdef WIN32
  326. return TryEnterCriticalSection(&CSMutex);
  327. #else
  328. return (pthread_mutex_trylock(&CSMutex) == 0);
  329. #endif
  330. }