Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

637 lines
12 KiB

  1. #ifndef _SHAREDMEMORY_H_
  2. #define _SHAREDMEMORY_H_
  3. int CircBuffWrite(BYTE *pbStart, int cbBuff, int obDst, BYTE *pbSrc, int cb);
  4. int CircBuffRead(BYTE *pbStart, int cbBuff, int obSrc, BYTE *pbDst, int cb);
  5. class SharedMemorySignature
  6. {
  7. public:
  8. void Ready()
  9. {
  10. m_fReady = TRUE;
  11. }
  12. void Sign(const char *sz)
  13. {
  14. strncpy(m_sz, sz, sizeof(m_sz));
  15. }
  16. void WaitUntilReady()
  17. {
  18. while (!m_fReady)
  19. Sleep(0);
  20. }
  21. char m_sz[4];
  22. long m_fReady;
  23. };
  24. class SharedMemoryLock
  25. {
  26. public:
  27. class PerProcessData
  28. {
  29. friend SharedMemoryLock;
  30. public:
  31. PerProcessData()
  32. {
  33. m_hWaitRead = 0;
  34. m_hWaitWrite = 0;
  35. m_hWaitNew = 0;
  36. }
  37. ~PerProcessData()
  38. {
  39. Close();
  40. }
  41. HRESULT Open(const TCHAR *szName)
  42. {
  43. TCHAR sz[MAX_PATH];
  44. // Create an auto-reset event for waiting readers
  45. wsprintf(sz, _TEXT("%s_R"), szName);
  46. m_hWaitRead = CreateEvent(NULL, FALSE, FALSE, sz);
  47. // Create an auto-reset event for waiting writers
  48. wsprintf(sz, _TEXT("%s_W"), szName);
  49. m_hWaitWrite = CreateEvent(NULL, FALSE, FALSE, sz);
  50. // Create an auto-reset event for those waiting for new data
  51. wsprintf(sz, _TEXT("%s_N"), szName);
  52. m_hWaitNew = CreateEvent(NULL, FALSE, FALSE, sz);
  53. }
  54. void Close()
  55. {
  56. if (m_hWaitRead != NULL)
  57. {
  58. CloseHandle(m_hWaitRead);
  59. m_hWaitRead = NULL;
  60. }
  61. if (m_hWaitWrite != NULL)
  62. {
  63. CloseHandle(m_hWaitWrite);
  64. m_hWaitWrite = NULL;
  65. }
  66. if (m_hWaitNew != NULL)
  67. {
  68. CloseHandle(m_hWaitNew);
  69. m_hWaitNew = NULL;
  70. }
  71. }
  72. protected:
  73. HANDLE m_hWaitRead;
  74. HANDLE m_hWaitWrite;
  75. HANDLE m_hWaitNew;
  76. };
  77. void Init()
  78. {
  79. m_lSpinLock = 0;
  80. m_cWaitingNew = 0;
  81. m_cReadersActive = 0;
  82. m_cReadersWaiting = 0;
  83. m_cWritersActive = 0;
  84. m_cWritersWaiting = 0;
  85. }
  86. DWORD WaitToRead(PerProcessData *pperprocess, DWORD dwMillisecs)
  87. {
  88. Lock();
  89. while (m_cWritersActive > 0)
  90. {
  91. // Can't read if there are any writers active
  92. m_cReadersWaiting++;
  93. Unlock();
  94. DWORD dw = WaitForSingleObject(pperprocess->m_hWaitRead, dwMillisecs);
  95. Lock();
  96. if (dw != WAIT_OBJECT_0)
  97. {
  98. m_cReadersWaiting--;
  99. Unlock();
  100. return dw;
  101. }
  102. }
  103. m_cReadersActive++;
  104. Unlock();
  105. return WAIT_OBJECT_0;
  106. }
  107. void ReadComplete(PerProcessData *pperprocess)
  108. {
  109. Lock();
  110. m_cReadersActive--;
  111. if ((m_cReadersActive == 0) && (m_cWritersWaiting > 0))
  112. {
  113. // Give a writer a chance.
  114. m_cWritersWaiting--;
  115. SetEvent(pperprocess->m_hWaitWrite);
  116. }
  117. Unlock();
  118. }
  119. DWORD WaitForNew(PerProcessData *pperprocess, DWORD dwMillisecs)
  120. {
  121. Lock();
  122. m_cWaitingNew++;
  123. Unlock();
  124. return WaitForSingleObject(pperprocess->m_hWaitNew, dwMillisecs);
  125. }
  126. DWORD WaitToWrite(PerProcessData *pperprocess, DWORD dwMillisecs)
  127. {
  128. Lock();
  129. while ((m_cWritersActive != 0) || (m_cReadersActive != 0))
  130. {
  131. // Can't write if there are any readers or any writers
  132. m_cWritersWaiting++;
  133. Unlock();
  134. DWORD dw = WaitForSingleObject(pperprocess->m_hWaitRead, dwMillisecs);
  135. Lock();
  136. if (dw != WAIT_OBJECT_0)
  137. {
  138. m_cWritersWaiting--;
  139. Unlock();
  140. return dw;
  141. }
  142. }
  143. m_cWritersActive++;
  144. Unlock();
  145. return WAIT_OBJECT_0;
  146. }
  147. void WriteComplete(PerProcessData *pperprocess, boolean fNewData)
  148. {
  149. Lock();
  150. m_cWritersActive--;
  151. if (fNewData)
  152. {
  153. // Release anybody who's waiting for new data.
  154. while (m_cWaitingNew > 0)
  155. {
  156. SetEvent(pperprocess->m_hWaitNew);
  157. m_cWaitingNew--;
  158. }
  159. }
  160. if (m_cReadersWaiting)
  161. {
  162. // Unblock all the readers.
  163. while (m_cReadersWaiting--)
  164. SetEvent(pperprocess->m_hWaitRead);
  165. }
  166. else if (m_cWritersWaiting)
  167. {
  168. // Unblock one writer.
  169. m_cWritersWaiting--;
  170. SetEvent(pperprocess->m_hWaitWrite);
  171. }
  172. Unlock();
  173. }
  174. protected:
  175. void Lock()
  176. {
  177. // Spin and get access to the shared memory
  178. while (InterlockedExchange(&m_lSpinLock, 1) != 0)
  179. Sleep(0);
  180. }
  181. void Unlock()
  182. {
  183. InterlockedExchange(&m_lSpinLock, 0);
  184. }
  185. long m_lSpinLock; // Used to gain access to this structure
  186. int m_cWaitingNew;
  187. int m_cReadersActive;
  188. int m_cReadersWaiting;
  189. int m_cWritersActive;
  190. int m_cWritersWaiting;
  191. };
  192. template <class TShared, int nLocks>
  193. class SharedMemory
  194. {
  195. public:
  196. SharedMemory()
  197. {
  198. }
  199. void Open(LPCTSTR lpName);
  200. void Close();
  201. TShared * SharedData()
  202. {
  203. return m_pvClient;
  204. }
  205. void InitLock(int iLock)
  206. {
  207. m_rglock[i].Init();
  208. }
  209. ~SharedMemory()
  210. {
  211. Close();
  212. }
  213. DWORD WaitToRead(int i, DWORD dwMilliseconds)
  214. {
  215. return m_rglock[i].WaitToRead(m_rglockperprocess[i], dwMilliseconds);
  216. }
  217. void ReadComplete(int i)
  218. {
  219. return m_rglock[i].ReadComplete(m_rglockperprocess[i]);
  220. }
  221. DWORD WaitForNew(int i, DWORD dwMillisecs)
  222. {
  223. return m_rglock[i].WaitForNew(m_rglockperprocess[i], dwMilliseconds);
  224. }
  225. DWORD WaitToWrite(int i, DWORD dwMillisecs)
  226. {
  227. return m_rglock[i].WaitToWrite(m_rglockperprocess[i], dwMilliseconds);
  228. }
  229. void WriteComplete(int i, boolean fNewData)
  230. {
  231. return m_rglock[i].WriteComplete(m_rglockperprocess[i], fNewData);
  232. }
  233. protected:
  234. HRESULT CreateFileView(LPCTSTR lpName);
  235. protected:
  236. SharedMemoryLock *m_rglock;
  237. SharedMemoryLock::PerProcessData m_rglockperprocess[nLocks];
  238. HANDLE m_hFileMap; // Handle to memory mapped file
  239. void *m_pvSharedMem;
  240. TShared *m_pvClient;
  241. };
  242. template <class TShared, int nLocks>
  243. void SharedMemory<TShared, nLocks>::Open(LPCTSTR lpName)
  244. {
  245. HRESULT hr;
  246. // Try to create the memory mapped file
  247. hr = CreateFileView(lpName);
  248. if (FAILED(hr))
  249. {
  250. Close();
  251. return;
  252. }
  253. for (int i = 0; i < nLocks; i++)
  254. {
  255. TCHAR sz[MAX_PATH];
  256. wsprintf(sz, _T("CLA_%s_%d"), lpName, i);
  257. m_rglockperprocess[i].Open(sz);
  258. }
  259. }
  260. template <class TShared, int nLocks>
  261. void SharedMemory<TShared, nLocks>::Close()
  262. {
  263. // Clean up
  264. if (m_pvSharedMem)
  265. {
  266. UnmapViewOfFile(m_pvSharedMem);
  267. m_pvSharedMem= NULL;
  268. m_rglock = NULL;
  269. m_pvClient = NULL;
  270. }
  271. if (m_hFileMap)
  272. {
  273. CloseHandle(m_hFileMap);
  274. m_hFileMap = NULL;
  275. }
  276. for (int i = 0; i < nLocks; i++)
  277. m_rglockperprocess[i].Close();
  278. }
  279. template <class TShared, int nLocks>
  280. HRESULT SharedMemory<TShared, nLocks>::CreateFileView(LPCTSTR lpName)
  281. {
  282. if (lpName == NULL)
  283. return E_INVALIDARG;
  284. int cb = sizeof(SharedMemorySignature) + nLocks*sizeof(SharedMemoryLock)
  285. + sizeof(TShared);
  286. m_hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
  287. PAGE_READWRITE, 0, cb, lpName);
  288. // Map a view of the file
  289. if (m_hFileMap)
  290. {
  291. DWORD dwLastError = GetLastError();
  292. m_pvSharedMem = MapViewOfFile(m_hFileMap, FILE_MAP_WRITE, 0, 0, 0);
  293. if (m_pvSharedMem)
  294. {
  295. m_psignature = (SharedMemorySignature *) m_pvSharedMem;
  296. m_rglock = (SharedMemoryLock *) (m_psignature + 1);
  297. m_pvClient = (TShared *) (m_rglock + nLocks);
  298. if (dwLastError != ERROR_ALREADY_EXISTS)
  299. {
  300. m_psignature->Sign("CLA");
  301. for (int i = 0; i < nLocks; i++)
  302. InitLock(i);
  303. m_psignature->Ready();
  304. }
  305. else
  306. {
  307. // It already exists; wait until it is initialized by the creator
  308. m_psignature->WaitUntilReady();
  309. }
  310. return S_OK;
  311. }
  312. }
  313. return E_FAIL; //UNDONE: Proper error code
  314. }
  315. template <int cReadersMax, int cbShared, int cbThread>
  316. class MulticastQueue
  317. {
  318. typedef MulticastQueue<cReadersMax, cbShared, cbThread> ThisClass;
  319. public:
  320. MulticastQueue()
  321. {
  322. m_iReader = -1;
  323. m_hCopySharedMemThread = 0;
  324. m_fRunCopySharedMemThread = FALSE;
  325. }
  326. HRESULT Open(LPCTSTR lpName)
  327. {
  328. m_shared.Open(lpName);
  329. m_pSharedBuff = m_shared.SharedData();
  330. m_iReader = m_pSharedBuff.AllocReader();
  331. StartCopySharedMemThread();
  332. }
  333. void StartCopySharedMemThread()
  334. {
  335. DWORD id;
  336. m_fRunCopySharedMemThread = TRUE;
  337. m_hCopySharedMemThread = CreateThread(NULL, 0, _CopySharedMemThread,
  338. (void *) this, 0, &id);
  339. }
  340. void StopCopySharedMemThread()
  341. {
  342. // Thread will exit once it sees this go to FALSE.
  343. m_fRunCopySharedMemThread = FALSE;
  344. }
  345. static DWORD WINAPI _CopySharedMemThread(LPVOID pv)
  346. {
  347. ThisClass *pThis = (ThisClass *) pv;
  348. return pThis->CopySharedMemThread();
  349. }
  350. HRESULT ReadShared(BYTE *pb, int cb)
  351. {
  352. HRESULT hr;
  353. while (m_pSharedBuff->CbAvailable() < cb)
  354. m_shared.WaitForNew(0, 0);
  355. hr = E_FAILED;
  356. while (FAILED(hr))
  357. {
  358. m_shared.WaitToRead(0, 0);
  359. hr = m_pSharedBuff->Read(pb, cb);
  360. m_shared.ReadComplete(0);
  361. }
  362. return S_OK;
  363. }
  364. DWORD CopySharedMemThread()
  365. {
  366. while (m_fRunCopySharedMemThread)
  367. {
  368. int cb;
  369. while (TRUE)
  370. {
  371. cb = m_pSharedBuff->CbAvailable();
  372. if (cb <= 0)
  373. m_shared.WaitForNew(0, 0);
  374. cb = min(m_ThreadBuff.CbFree(), cb);
  375. if (cb > 0)
  376. break;
  377. // UNDONE : wait for space available in thread buffer
  378. }
  379. m_shared.WaitToRead(0, 0);
  380. m_pSharedBuff->Read(&buff, cb);
  381. m_ThreadBuff->Write(&buff, cb);
  382. }
  383. return 0;
  384. }
  385. class ThreadBuffer
  386. {
  387. public:
  388. ThreadBuffer()
  389. {
  390. m_obRead = 0;
  391. m_obWrite = 0;
  392. }
  393. int CbAvailable()
  394. {
  395. int cb = m_obWrite - m_obRead;
  396. if (cb < 0)
  397. cb += cbThread;
  398. return cb;
  399. }
  400. HRESULT Read(BYTE *pb, int cb)
  401. {
  402. if (CbAvailable() < cb)
  403. return E_FAIL;
  404. m_obRead = CircBuffRead(m_rgb, cbThread, m_obRead, pb, cb);
  405. return S_OK;
  406. }
  407. HRESULT Write(BYTE *pb, int cb)
  408. {
  409. if (cbThread - CbAvailable() < cb)
  410. return E_FAIL;
  411. m_obWrite = CircBuffWrite(m_rgb, cbThread, m_obWrite, pb, cb);
  412. return S_OK;
  413. }
  414. protected:
  415. int m_obRead;
  416. int m_obWrite;
  417. BYTE m_rgb[cbThread];
  418. };
  419. class SharedBuffer
  420. {
  421. void Init()
  422. {
  423. m_cReadersMac = 0;
  424. m_oWriteCur = 0;
  425. for (int i = 0; i < cReadersMax; i++)
  426. m_rgoReadCur[i] = -1;
  427. }
  428. int CbAvailable(int i)
  429. {
  430. if (m_rgoReadCur[i] == -1)
  431. return 0;
  432. int cb = m_oWriteCur - m_rgoReadCur[i];
  433. if (cb < 0)
  434. cb += cbShared;
  435. return cb;
  436. }
  437. HRESULT Write(BYTE *pb, int cb)
  438. {
  439. int cbFree = cbShared;
  440. for (int i = 0; i < m_cReadersMac; i++)
  441. {
  442. int cbCur = cbShared - CbAvailable(i);
  443. if (cbCur < cbFree)
  444. cbFree = cbCur;
  445. }
  446. if (cbFree < cb)
  447. return E_FAIL;
  448. m_obWrite = CircBuffWrite(m_rgb, cbShared, m_obWrite, pb, cb);
  449. return S_OK;
  450. }
  451. HRESULT Read(int i, BYTE *pb, int cb, int *pcbRead)
  452. {
  453. _ASSERTE((i >= 0) && (i < m_cReadersMac) && (m_rgoReadCur[i] != -1));
  454. cb = min(cb, CbAvailable(i));
  455. if (pcbRead != NULL)
  456. *pcbRead = cb;
  457. if (cb == 0)
  458. return S_FALSE;
  459. m_rgoReadCur[i] = CircBuffRead(m_rgb, cbShared, m_rgoReadCur[i], pb, cb);
  460. return S_OK;
  461. }
  462. int AllocReader()
  463. {
  464. int i;
  465. for (i = 0; (i < m_cReadersMac) && (m_rgoReadCur[i] == -1); i++)
  466. ;
  467. if (i >= cReadersMax)
  468. return -1;
  469. if (i >= m_cReadersMac)
  470. m_iReaderMac = i + 1;
  471. m_rgoReadCur[i] = m_oWriteCur;
  472. return i;
  473. }
  474. int m_iReaderMac;
  475. int m_oWriteCur;
  476. int m_rgoReadCur[cReadersMax];
  477. BYTE m_rgb[cbShared];
  478. };
  479. HRESULT Read(BYTE *pb, int cb, int *pcbRead, boolean fWait)
  480. {
  481. *pcbRead = 0;
  482. while (cb > 0)
  483. {
  484. int cbRead = min(cb, m_ThreadBuff.CbAvailable());
  485. if (cbRead > 0)
  486. {
  487. m_ThreadBuff.Read(pb, cbRead);
  488. pb += cbRead;
  489. *pcbRead += cbRead;
  490. cb -= cbRead;
  491. }
  492. else
  493. {
  494. if (!fWait)
  495. return S_FALSE;
  496. m_ThreadBuff.WaitForNew(0);
  497. }
  498. }
  499. return S_OK;
  500. }
  501. HRESULT Write(BYTE *pb, int cb)
  502. {
  503. HRESULT hr = E_FAIL;
  504. if (cb > cbShared)
  505. return E_FAIL;
  506. while (FAILED(hr))
  507. {
  508. m_shared.WaitToWrite(0, 0);
  509. hr = m_pSharedBuff->Write(pb, cb);
  510. m_shared.WriteComplete(0, SUCCEEDED(hr));
  511. }
  512. return hr;
  513. }
  514. int ReaderNumber()
  515. {
  516. return m_iReader;
  517. }
  518. protected:
  519. int m_iReader;
  520. SharedMemory<SharedBuffer, 1> m_shared;
  521. SharedBuffer *m_pSharedBuff;
  522. ThreadBuffer m_ThreadBuff;
  523. BOOL m_fRunCopySharedMemThread;
  524. HANDLE m_hCopySharedMemThread;
  525. };
  526. #endif // _SHAREDMEMORY_H_