SWMRG.CPP 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*-------------------------------------------------------------------------
  2. * src\fedsrv\SWMRG.CPP
  3. *
  4. * Single Writer, Multiple Reader w/ Guard
  5. *
  6. * Owner:
  7. *
  8. * Copyright 1986-1998 Microsoft Corporation, All Rights Reserved
  9. *-----------------------------------------------------------------------*/
  10. /*
  11. #include <windows.h>
  12. #include <string.h>
  13. #include <tchar.h>
  14. #include "SWMRG.H" // The header file
  15. */
  16. #include "pch.h"
  17. /*-------------------------------------------------------------------------
  18. * ConstructObjName
  19. *-------------------------------------------------------------------------
  20. * Purpose:
  21. * Just construct a name for the kernel object
  22. *
  23. * Returns:
  24. * the munged name
  25. */
  26. static LPCTSTR ConstructObjName (LPCTSTR lpszPrefix, LPCTSTR lpszSuffix,
  27. LPTSTR lpszFullName, size_t cbFullName, bool * pfOk)
  28. {
  29. *pfOk = true; // Assume success.
  30. if (lpszSuffix == NULL)
  31. return(NULL);
  32. if ((_tcslen(lpszPrefix) + _tcslen(lpszSuffix)) >= cbFullName)
  33. {
  34. // If the strings will overflow the buffer,
  35. // indicate an error.
  36. *pfOk = false;
  37. return NULL;
  38. }
  39. _tcscpy(lpszFullName, lpszPrefix);
  40. _tcscat(lpszFullName, lpszSuffix);
  41. return(lpszFullName);
  42. }
  43. /*-------------------------------------------------------------------------
  44. * FSWMRGInitialize
  45. *-------------------------------------------------------------------------
  46. * Purpose:
  47. * Initializes a SWMRG structure. This structure must be
  48. * initialized before any writer or reader threads attempt
  49. * to wait on it.
  50. * The structure must be allocated by the application and
  51. * the structure's address is passed as the first parameter.
  52. * The lpszName parameter is the name of the object. Pass
  53. * NULL if you do not want to share the object.
  54. *
  55. * Returns:
  56. * success
  57. */
  58. bool FSWMRGInitialize(PSWMRG pSWMRG, LPCTSTR lpszName)
  59. {
  60. TCHAR szFullObjName[100];
  61. LPCTSTR lpszObjName;
  62. bool fOk;
  63. // Initialize all data members to NULL so that we can
  64. // accurately check whether an error has occured.
  65. pSWMRG->hMutexNoWriter = NULL;
  66. pSWMRG->hEventNoReaders = NULL;
  67. pSWMRG->hSemNumReaders = NULL;
  68. // This mutex guards access to the other objects
  69. // managed by this data structure and also indicates
  70. // whether there any writer threads are writing.
  71. // Initially no thread owns the mutex.
  72. lpszObjName = ConstructObjName(__TEXT("SWMRGMutexNoWriter"), lpszName,
  73. szFullObjName, ARRAY_SIZE(szFullObjName), &fOk);
  74. if (fOk)
  75. pSWMRG->hMutexNoWriter = CreateMutex(NULL, FALSE, lpszObjName);
  76. // Create the manual-reset event that is signalled when
  77. // no reader threads are reading.
  78. // Initially no reader threads are reading.
  79. lpszObjName = ConstructObjName(__TEXT("SWMRGEventNoReaders"), lpszName,
  80. szFullObjName, ARRAY_SIZE(szFullObjName), &fOk);
  81. if (fOk)
  82. pSWMRG->hEventNoReaders = CreateEvent(NULL, TRUE, TRUE, lpszObjName);
  83. // Initialize the variable that indicates the number of
  84. // reader threads that are reading.
  85. // Initially no reader threads are reading.
  86. lpszObjName = ConstructObjName(__TEXT("SWMRGSemNumReaders"), lpszName,
  87. szFullObjName, ARRAY_SIZE(szFullObjName), &fOk);
  88. if (fOk)
  89. pSWMRG->hSemNumReaders = CreateSemaphore(NULL, 0, 0x7FFFFFFF, lpszObjName);
  90. if (NULL == pSWMRG->hMutexNoWriter ||
  91. NULL == pSWMRG->hEventNoReaders ||
  92. NULL == pSWMRG->hSemNumReaders)
  93. {
  94. // If a synchronization object could not be created,
  95. // destroy any created objects and return failure.
  96. SWMRGDelete(pSWMRG);
  97. fOk = false;
  98. }
  99. else
  100. {
  101. fOk = true;
  102. }
  103. // Return TRUE upon success, FALSE upon failure.
  104. return(fOk);
  105. }
  106. /*-------------------------------------------------------------------------
  107. * SWMRGDelete
  108. *-------------------------------------------------------------------------
  109. * Purpose:
  110. * Deletes the system resources associated with a SWMRG
  111. * structure. The structure must be deleted only when
  112. * no writer or reader threads in the calling process
  113. * will wait on it.
  114. */
  115. void SWMRGDelete(PSWMRG pSWMRG)
  116. {
  117. // Destroy any synchronization objects that were
  118. // successfully created.
  119. if (pSWMRG->hMutexNoWriter)
  120. CloseHandle(pSWMRG->hMutexNoWriter);
  121. if (pSWMRG->hEventNoReaders)
  122. CloseHandle(pSWMRG->hEventNoReaders);
  123. if (pSWMRG->hSemNumReaders)
  124. CloseHandle(pSWMRG->hSemNumReaders);
  125. }
  126. /*-------------------------------------------------------------------------
  127. * SWMRGWaitToWrite
  128. *-------------------------------------------------------------------------
  129. * Purpose:
  130. * A writer thread calls this function to know when
  131. * it can successfully write to the shared data.
  132. *
  133. * Returns:
  134. * WaitForMultipleObjects()
  135. */
  136. DWORD SWMRGWaitToWrite(PSWMRG pSWMRG, DWORD dwTimeout)
  137. {
  138. DWORD dw;
  139. HANDLE rgHandles[2];
  140. // We can write if the following are true:
  141. // 1. The mutex guard is available and
  142. // no other threads are writing.
  143. // 2. No threads are reading.
  144. rgHandles[0] = pSWMRG->hMutexNoWriter;
  145. rgHandles[1] = pSWMRG->hEventNoReaders;
  146. dw = WaitForMultipleObjects(2, rgHandles, TRUE, dwTimeout);
  147. if (dw != WAIT_TIMEOUT)
  148. {
  149. // This thread can write to the shared data.
  150. // Because a writer thread is writing, the mutex should not
  151. // not be released. This stops other writers and readers.
  152. }
  153. return(dw);
  154. }
  155. /*-------------------------------------------------------------------------
  156. * SWMRGDoneWriting
  157. *-------------------------------------------------------------------------
  158. * Purpose:
  159. * A writer thread calls this function to let other threads
  160. * know that it no longer needs to write to the shared data.
  161. */
  162. void SWMRGDoneWriting(PSWMRG pSWMRG)
  163. {
  164. // Presumably, a writer thread calling this function has
  165. // successfully called WaitToWrite. This means that we
  166. // do not have to wait on any synchronization objects
  167. // here because the writer already owns the mutex.
  168. // Allow other writer/reader threads to use
  169. // the SWMRG synchronization object.
  170. ReleaseMutex(pSWMRG->hMutexNoWriter);
  171. }
  172. /*-------------------------------------------------------------------------
  173. * SWMRGWaitToRead
  174. *-------------------------------------------------------------------------
  175. * Purpose:
  176. * A reader thread calls this function to know when
  177. * it can successfully read the shared data.
  178. *
  179. * Returns:
  180. * WaitForSingleObject()
  181. */
  182. DWORD SWMRGWaitToRead(PSWMRG pSWMRG, DWORD dwTimeout)
  183. {
  184. DWORD dw;
  185. LONG lPreviousCount;
  186. // We can read if the mutex guard is available
  187. // and no threads are writing.
  188. dw = WaitForSingleObject(pSWMRG->hMutexNoWriter, dwTimeout);
  189. if (dw != WAIT_TIMEOUT)
  190. {
  191. // This thread can read from the shared data.
  192. // Increment the number of reader threads.
  193. ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lPreviousCount);
  194. if (lPreviousCount == 0)
  195. {
  196. // If this is the first reader thread,
  197. // set our event to reflect this.
  198. ResetEvent(pSWMRG->hEventNoReaders);
  199. }
  200. // Allow other writer/reader threads to use
  201. // the SWMRG synchronization object.
  202. ReleaseMutex(pSWMRG->hMutexNoWriter);
  203. }
  204. return(dw);
  205. }
  206. /*-------------------------------------------------------------------------
  207. * SWMRGDoneReading
  208. *-------------------------------------------------------------------------
  209. * Purpose:
  210. * A reader thread calls this function to let other threads
  211. * know when it no longer needs to read the shared data.
  212. */
  213. void SWMRGDoneReading(PSWMRG pSWMRG)
  214. {
  215. bool fLastReader;
  216. HANDLE rgHandles[2];
  217. // We can stop reading if the mutex guard is available,
  218. // but when we stop reading we must also decrement the
  219. // number of reader threads.
  220. rgHandles[0] = pSWMRG->hMutexNoWriter;
  221. rgHandles[1] = pSWMRG->hSemNumReaders;
  222. WaitForMultipleObjects(2, rgHandles, TRUE, INFINITE);
  223. fLastReader = WAIT_TIMEOUT == WaitForSingleObject(pSWMRG->hSemNumReaders, 0);
  224. if (fLastReader)
  225. {
  226. // If this is the last reader thread,
  227. // set our event to reflect this.
  228. SetEvent(pSWMRG->hEventNoReaders);
  229. }
  230. else
  231. {
  232. // If this is NOT the last reader thread, we successfully
  233. // waited on the semaphore. We must release the semaphore
  234. // so that the count accurately reflects the number
  235. // of reader threads.
  236. ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, NULL);
  237. }
  238. // Allow other writer/reader threads to use
  239. // the SWMRG synchronization object.
  240. ReleaseMutex(pSWMRG->hMutexNoWriter);
  241. }