Mutex.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. return;
  98. }
  99. i++;
  100. #endif
  101. Sleep(1);
  102. }
  103. }
  104. void Mutex::releasereadlock(const char* function, int32 line) {
  105. //Wait for the readcount lock
  106. CSRead.lock();
  107. //Lower the readcount by one, when readcount is 0 writers may start writing
  108. readers--;
  109. CSRead.unlock();
  110. #ifdef DEBUG
  111. CSStack.lock();
  112. if (function) {
  113. map<string, int32>::iterator itr = stack.find((string)function);
  114. if (itr != stack.end()) {
  115. if (--(itr->second) == 0) {
  116. stack.erase(itr);
  117. }
  118. }
  119. }
  120. CSStack.unlock();
  121. #endif
  122. }
  123. bool Mutex::tryreadlock(const char* function) {
  124. //This returns true if able to instantly obtain a readlock, false if not
  125. CSRead.lock();
  126. if (!writing) {
  127. readers++;
  128. CSRead.unlock();
  129. }
  130. else {
  131. CSRead.unlock();
  132. return false;
  133. }
  134. #ifdef DEBUG
  135. CSStack.lock();
  136. if (function)
  137. stack[(string)function]++;
  138. CSStack.unlock();
  139. #endif
  140. return true;
  141. }
  142. void Mutex::writelock(const char* function, int32 line) {
  143. //Wait until the writer lock becomes available, then we can be the only writer!
  144. #ifdef DEBUG
  145. int32 i = 0;
  146. #endif
  147. while (!CSWrite.trylock()) {
  148. #ifdef DEBUG
  149. if (i > MUTEX_TIMEOUT_MILLISECONDS) {
  150. 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);
  151. LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
  152. map<string, int32>::iterator itr;
  153. CSStack.lock();
  154. for (itr = stack.begin(); itr != stack.end(); itr++) {
  155. if (itr->second > 0 && itr->first.length() > 0)
  156. LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
  157. }
  158. CSStack.unlock();
  159. i = 0;
  160. continue;
  161. }
  162. i++;
  163. #endif
  164. Sleep(1);
  165. }
  166. waitReaders(function, line);
  167. #ifdef DEBUG
  168. CSStack.lock();
  169. if (function)
  170. stack[(string)function]++;
  171. CSStack.unlock();
  172. #endif
  173. }
  174. void Mutex::releasewritelock(const char* function, int32 line) {
  175. //Wait for the readcount lock
  176. CSRead.lock();
  177. //Readers are aloud again
  178. writing = false;
  179. CSRead.unlock();
  180. //Allow other writers to write
  181. CSWrite.unlock();
  182. #ifdef DEBUG
  183. CSStack.lock();
  184. if (function) {
  185. map<string, int32>::iterator itr = stack.find((string)function);
  186. if (itr != stack.end()) {
  187. if (--(itr->second) == 0) {
  188. stack.erase(itr);
  189. }
  190. }
  191. }
  192. CSStack.unlock();
  193. #endif
  194. }
  195. bool Mutex::trywritelock(const char* function) {
  196. //This returns true if able to instantly obtain a writelock, false if not
  197. if (CSWrite.trylock()) {
  198. CSRead.lock();
  199. if (readers == 0)
  200. writing = true;
  201. CSRead.unlock();
  202. if (!writing) {
  203. CSWrite.unlock();
  204. return false;
  205. }
  206. }
  207. else
  208. return false;
  209. #ifdef DEBUG
  210. CSStack.lock();
  211. if (function)
  212. stack[(string)function]++;
  213. CSStack.unlock();
  214. #endif
  215. return true;
  216. }
  217. void Mutex::waitReaders(const char* function, int32 line)
  218. {
  219. //Wait for all current readers to stop, then we can write!
  220. #ifdef DEBUG
  221. int32 i = 0;
  222. #endif
  223. while (true)
  224. {
  225. CSRead.lock();
  226. if (readers == 0)
  227. {
  228. writing = true;
  229. CSRead.unlock();
  230. break;
  231. }
  232. CSRead.unlock();
  233. #ifdef DEBUG
  234. if (i > MUTEX_TIMEOUT_MILLISECONDS) {
  235. 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);
  236. LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
  237. map<string, int32>::iterator itr;
  238. CSStack.lock();
  239. for (itr = stack.begin(); itr != stack.end(); itr++) {
  240. if (itr->second > 0 && itr->first.length() > 0)
  241. LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
  242. }
  243. CSStack.unlock();
  244. i = 0;
  245. continue;
  246. }
  247. i++;
  248. #endif
  249. Sleep(1);
  250. }
  251. }
  252. LockMutex::LockMutex(Mutex* in_mut, bool iLock) {
  253. mut = in_mut;
  254. locked = iLock;
  255. if (locked) {
  256. mut->lock();
  257. }
  258. }
  259. LockMutex::~LockMutex() {
  260. if (locked) {
  261. mut->unlock();
  262. }
  263. }
  264. void LockMutex::unlock() {
  265. if (locked)
  266. mut->unlock();
  267. locked = false;
  268. }
  269. void LockMutex::lock() {
  270. if (!locked)
  271. mut->lock();
  272. locked = true;
  273. }
  274. CriticalSection::CriticalSection(int attribute) {
  275. #ifdef WIN32
  276. InitializeCriticalSection(&CSMutex);
  277. #else
  278. pthread_mutexattr_init(&type_attribute);
  279. switch (attribute)
  280. {
  281. case MUTEX_ATTRIBUTE_FAST:
  282. pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_FAST_NP);
  283. break;
  284. case MUTEX_ATTRIBUTE_RECURSIVE:
  285. pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_RECURSIVE_NP);
  286. break;
  287. case MUTEX_ATTRIBUTE_ERRORCHK:
  288. pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_ERRORCHECK_NP);
  289. break;
  290. default:
  291. LogWrite(MUTEX__DEBUG, 0, "Critical Section", "Invalid mutex attribute type! Using PTHREAD_MUTEX_FAST_NP");
  292. pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_FAST_NP);
  293. break;
  294. }
  295. pthread_mutex_init(&CSMutex, &type_attribute);
  296. #endif
  297. }
  298. CriticalSection::~CriticalSection() {
  299. #ifdef WIN32
  300. DeleteCriticalSection(&CSMutex);
  301. #else
  302. pthread_mutex_destroy(&CSMutex);
  303. pthread_mutexattr_destroy(&type_attribute);
  304. #endif
  305. }
  306. void CriticalSection::lock() {
  307. //Waits for a lock on this critical section
  308. #ifdef WIN32
  309. EnterCriticalSection(&CSMutex);
  310. #else
  311. pthread_mutex_lock(&CSMutex);
  312. #endif
  313. }
  314. void CriticalSection::unlock() {
  315. //Gets rid of one of the current thread's locks on this critical section
  316. #ifdef WIN32
  317. LeaveCriticalSection(&CSMutex);
  318. #else
  319. pthread_mutex_unlock(&CSMutex);
  320. #endif
  321. }
  322. bool CriticalSection::trylock() {
  323. //Returns true if able to instantly get a lock on this critical section, false if not
  324. #ifdef WIN32
  325. return TryEnterCriticalSection(&CSMutex);
  326. #else
  327. return (pthread_mutex_trylock(&CSMutex) == 0);
  328. #endif
  329. }