critsec.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program 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. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "critsec.h"
  19. #include <assert.h>
  20. #include "wlib/wdebug.h"
  21. CritSec::CritSec()
  22. {
  23. #ifdef _UNIX
  24. pthread_mutex_init(&Mutex_, NULL);
  25. RefCount_ = 0;
  26. #elif defined(_WIN32)
  27. InitializeCriticalSection(&CritSec_);
  28. #endif
  29. }
  30. CritSec::~CritSec()
  31. {
  32. #ifdef _UNIX
  33. pthread_mutex_destroy(&Mutex_);
  34. #elif defined(_WIN32)
  35. DeleteCriticalSection(&CritSec_);
  36. #endif
  37. }
  38. // The "lock" function blocks until the mutex is available.
  39. // Returns 0 on success, error code on error.
  40. //
  41. // A thread that already has a lock will increment a reference count if it calls
  42. // lock again. It must then call unlock() enough times to get the reference to 0.
  43. //
  44. // If refcount is not null you can get the current ref counter after the lock.
  45. //
  46. sint32 CritSec::lock(int *refcount) RO
  47. {
  48. #ifdef _UNIX
  49. sint32 status;
  50. // I TRY to get the lock. IF I succeed, OR if I fail because
  51. // I already have the lock, I just increment the reference
  52. // count and return.
  53. if (((status = pthread_mutex_trylock(&Mutex_)) == 0) ||
  54. ((status == EBUSY) && (ThreadId_ == pthread_self())))
  55. {
  56. ThreadId_ = pthread_self();
  57. RefCount_++;
  58. if (refcount)
  59. *refcount=RefCount_;
  60. return(0);
  61. }
  62. // Otherwise, I wait for the lock.
  63. if ((status = pthread_mutex_lock(&Mutex_)) == 0)
  64. {
  65. assert(RefCount_ == 0);
  66. ThreadId_ = pthread_self();
  67. RefCount_++;
  68. }
  69. else
  70. {
  71. ERRMSG("pthread_mutex_lock: " << strerror(errno));
  72. }
  73. if (refcount)
  74. *refcount=RefCount_;
  75. return(status);
  76. #elif defined(_WIN32)
  77. // TOFIX update the refcount
  78. EnterCriticalSection(&CritSec_);
  79. return(0);
  80. #else
  81. #error Must define either _WIN32 or _UNIX
  82. #endif
  83. }
  84. // The "unlock" function release the critical section.
  85. sint32 CritSec::unlock(void) RO
  86. {
  87. #ifdef _UNIX
  88. sint32 status = 0;
  89. assert(RefCount_ >= 0);
  90. if (RefCount_ <= 0)
  91. {
  92. //ERRMSG("unlocking unlocked mutex!");
  93. return(-1);
  94. }
  95. ///assert(ThreadId_ == pthread_self());
  96. if (ThreadId_ != pthread_self())
  97. {
  98. WRNMSG("tried to unlock a mutex not owned by self");
  99. return(-1);
  100. }
  101. if (--RefCount_ == 0)
  102. {
  103. // Set thread id to zero -- we're going to release mutex
  104. ThreadId_ = (pthread_t)0;
  105. // Unlock the mutex.
  106. if ((status = pthread_mutex_unlock(&Mutex_)) != 0)
  107. ERRMSG("pthread_mutex_lock: " << strerror(errno));
  108. }
  109. return status;
  110. #elif defined(_WIN32)
  111. LeaveCriticalSection(&CritSec_);
  112. return(0);
  113. #endif
  114. }