x86UNIXMutex.cc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/console.h"
  23. #include "platformX86UNIX/platformX86UNIX.h"
  24. #include "platform/threads/thread.h"
  25. #include "platform/threads/mutex.h"
  26. #include "platformX86UNIX/x86UNIXMutex.h"
  27. #include "memory/safeDelete.h"
  28. #include <pthread.h>
  29. #include <sys/stat.h>
  30. #include <unistd.h>
  31. #include <fcntl.h>
  32. #include <errno.h>
  33. ProcessMutex::ProcessMutex()
  34. {
  35. mFD = -1;
  36. }
  37. ProcessMutex::~ProcessMutex()
  38. {
  39. release();
  40. }
  41. bool ProcessMutex::acquire(const char *mutexName)
  42. {
  43. if (mFD != -1)
  44. return false;
  45. dSprintf(
  46. mLockFileName, LockFileNameSize,
  47. "/tmp/%s.lock", mutexName);
  48. mFD = open(mLockFileName,
  49. O_CREAT | O_RDWR,
  50. S_IRUSR | S_IRGRP | S_IROTH |
  51. S_IWUSR | S_IWGRP | S_IWOTH);
  52. if (mFD == -1)
  53. {
  54. Con::printf("Couldn't open file: %s", mLockFileName);
  55. return false;
  56. }
  57. struct flock lock;
  58. //lock.l_type = F_RDLCK;
  59. lock.l_type = F_WRLCK;
  60. lock.l_whence = SEEK_SET;
  61. lock.l_start = 0;
  62. lock.l_len = 0;
  63. lock.l_pid = getpid();
  64. if (fcntl(mFD, F_SETLK, &lock) == -1)
  65. {
  66. Con::printf("Couldn't lock file: %s, %s",
  67. mLockFileName, strerror(errno));
  68. if (fcntl(mFD, F_GETLK, &lock) != -1)
  69. Con::printf("Lock owned by pid: %d", lock.l_pid);
  70. Con::printf("Remove the file if lock is stale");
  71. close(mFD);
  72. mFD = -1;
  73. return false;
  74. }
  75. return true;
  76. }
  77. void ProcessMutex::release()
  78. {
  79. if (mFD != -1)
  80. {
  81. close(mFD);
  82. mFD = -1;
  83. unlink(mLockFileName);
  84. }
  85. }
  86. //-----------------------------------------------------------------------------
  87. struct PlatformMutexData
  88. {
  89. pthread_mutex_t mMutex;
  90. bool locked;
  91. U32 lockedByThread;
  92. };
  93. //-----------------------------------------------------------------------------
  94. Mutex::Mutex()
  95. {
  96. bool ok;
  97. // Create the mutex data.
  98. mData = new PlatformMutexData;
  99. // Initialize the system mutex.
  100. pthread_mutexattr_t attr;
  101. ok = pthread_mutexattr_init(&attr);
  102. ok = pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
  103. ok = pthread_mutex_init(&(mData->mMutex),&attr);
  104. // Sanity!
  105. AssertFatal(ok == 0, "Mutex() failed: pthread_mutex_init() failed.");
  106. // Set the initial mutex state.
  107. mData->locked = false;
  108. mData->lockedByThread = 0;
  109. }
  110. //-----------------------------------------------------------------------------
  111. Mutex::~Mutex()
  112. {
  113. // Destroy the system mutex.
  114. const bool ok = pthread_mutex_destroy( &(mData->mMutex) );
  115. // Sanity!
  116. AssertFatal(ok == 0, "~Mutex() failed: pthread_mutex_destroy() failed.");
  117. // Delete the mutex data.
  118. SAFE_DELETE( mData );
  119. }
  120. //-----------------------------------------------------------------------------
  121. bool Mutex::lock( bool block )
  122. {
  123. // Is this a blocking lock?
  124. if( block )
  125. {
  126. // Yes, so block until mutex can be locked.
  127. const bool ok = pthread_mutex_lock( &(mData->mMutex) );
  128. // Sanity!
  129. AssertFatal( ok != EINVAL, "Mutex::lockMutex() failed: invalid mutex.");
  130. AssertFatal( ok != EDEADLK, "Mutex::lockMutex() failed: system detected a deadlock!");
  131. AssertFatal( ok == 0, "Mutex::lockMutex() failed: pthread_mutex_lock() failed -- unknown reason.");
  132. }
  133. else
  134. {
  135. // No, so attempt to lock the thread without blocking.
  136. const bool ok = pthread_mutex_trylock( &(mData->mMutex) );
  137. // returns EBUSY if mutex was locked by another thread,
  138. // returns EINVAL if mutex was not a valid mutex pointer,
  139. // returns 0 if lock succeeded.
  140. // Sanity!
  141. AssertFatal( ok != EINVAL, "Mutex::lockMutex(non blocking) failed: invalid mutex.");
  142. // Finish if we couldn't lock the mutex.
  143. if( ok != 0 )
  144. return false;
  145. AssertFatal( ok == 0, "Mutex::lockMutex(non blocking) failed: pthread_mutex_trylock() failed -- unknown reason.");
  146. }
  147. // Flag as locked by the current thread.
  148. mData->locked = true;
  149. mData->lockedByThread = ThreadManager::getCurrentThreadId();
  150. return true;
  151. }
  152. //-----------------------------------------------------------------------------
  153. void Mutex::unlock()
  154. {
  155. // Unlock the thread.
  156. const bool ok = pthread_mutex_unlock( &(mData->mMutex) );
  157. // Sanity!
  158. AssertFatal( ok == 0, "Mutex::unlockMutex() failed: pthread_mutex_unlock() failed.");
  159. // Flag as unlocked.
  160. mData->locked = false;
  161. mData->lockedByThread = 0;
  162. }