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. return;
  160. }
  161. i++;
  162. #endif
  163. Sleep(1);
  164. }
  165. waitReaders(function, line);
  166. #ifdef DEBUG
  167. CSStack.lock();
  168. if (function)
  169. stack[(string)function]++;
  170. CSStack.unlock();
  171. #endif
  172. }
  173. void Mutex::releasewritelock(const char* function, int32 line){
  174. //Wait for the readcount lock
  175. CSRead.lock();
  176. //Readers are aloud again
  177. writing = false;
  178. CSRead.unlock();
  179. //Allow other writers to write
  180. CSWrite.unlock();
  181. #ifdef DEBUG
  182. CSStack.lock();
  183. if (function){
  184. map<string, int32>::iterator itr = stack.find((string)function);
  185. if (itr != stack.end()){
  186. if (--(itr->second) == 0){
  187. stack.erase(itr);
  188. }
  189. }
  190. }
  191. CSStack.unlock();
  192. #endif
  193. }
  194. bool Mutex::trywritelock(const char* function){
  195. //This returns true if able to instantly obtain a writelock, false if not
  196. if (CSWrite.trylock()){
  197. CSRead.lock();
  198. if (readers == 0)
  199. writing = true;
  200. CSRead.unlock();
  201. if (!writing){
  202. CSWrite.unlock();
  203. return false;
  204. }
  205. }
  206. else
  207. return false;
  208. #ifdef DEBUG
  209. CSStack.lock();
  210. if (function)
  211. stack[(string)function]++;
  212. CSStack.unlock();
  213. #endif
  214. return true;
  215. }
  216. void Mutex::waitReaders(const char* function, int32 line)
  217. {
  218. //Wait for all current readers to stop, then we can write!
  219. #ifdef DEBUG
  220. int32 i = 0;
  221. #endif
  222. CSRead.lock();
  223. writing = true;
  224. CSRead.unlock();
  225. while (true)
  226. {
  227. CSRead.lock();
  228. if (readers == 0)
  229. {
  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. return;
  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. }