PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/webrtc/test/channel_transport/udp_socket2_manager_win.cc

https://github.com/rillian/webrtc
C++ | 661 lines | 582 code | 52 blank | 27 comment | 78 complexity | 5fffb3350f27fb2ad1e223979a44483a MD5 | raw file
Possible License(s): BSD-3-Clause, CC-BY-SA-3.0
  1. /*
  2. * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #include "webrtc/test/channel_transport/udp_socket2_manager_win.h"
  11. #include <assert.h>
  12. #include <stdio.h>
  13. #include "webrtc/system_wrappers/interface/aligned_malloc.h"
  14. #include "webrtc/test/channel_transport/udp_socket2_win.h"
  15. namespace webrtc {
  16. namespace test {
  17. uint32_t UdpSocket2ManagerWindows::_numOfActiveManagers = 0;
  18. bool UdpSocket2ManagerWindows::_wsaInit = false;
  19. UdpSocket2ManagerWindows::UdpSocket2ManagerWindows()
  20. : UdpSocketManager(),
  21. _id(-1),
  22. _stopped(false),
  23. _init(false),
  24. _pCrit(CriticalSectionWrapper::CreateCriticalSection()),
  25. _ioCompletionHandle(NULL),
  26. _numActiveSockets(0),
  27. _event(EventWrapper::Create())
  28. {
  29. _managerNumber = _numOfActiveManagers++;
  30. if(_numOfActiveManagers == 1)
  31. {
  32. WORD wVersionRequested = MAKEWORD(2, 2);
  33. WSADATA wsaData;
  34. _wsaInit = WSAStartup(wVersionRequested, &wsaData) == 0;
  35. // TODO (hellner): seems safer to use RAII for this. E.g. what happens
  36. // if a UdpSocket2ManagerWindows() created and destroyed
  37. // without being initialized.
  38. }
  39. }
  40. UdpSocket2ManagerWindows::~UdpSocket2ManagerWindows()
  41. {
  42. WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
  43. "UdpSocket2ManagerWindows(%d)::~UdpSocket2ManagerWindows()",
  44. _managerNumber);
  45. if(_init)
  46. {
  47. _pCrit->Enter();
  48. if(_numActiveSockets)
  49. {
  50. _pCrit->Leave();
  51. _event->Wait(INFINITE);
  52. }
  53. else
  54. {
  55. _pCrit->Leave();
  56. }
  57. StopWorkerThreads();
  58. // All threads are stopped. Safe to delete them.
  59. ListItem* pItem = NULL;
  60. while((pItem = _workerThreadsList.First()) != NULL)
  61. {
  62. delete static_cast<UdpSocket2WorkerWindows*>(pItem->GetItem());
  63. _workerThreadsList.PopFront();
  64. }
  65. _ioContextPool.Free();
  66. _numOfActiveManagers--;
  67. if(_ioCompletionHandle)
  68. {
  69. CloseHandle(_ioCompletionHandle);
  70. }
  71. if (_numOfActiveManagers == 0)
  72. {
  73. if(_wsaInit)
  74. {
  75. WSACleanup();
  76. }
  77. }
  78. }
  79. if(_pCrit)
  80. {
  81. delete _pCrit;
  82. }
  83. if(_event)
  84. {
  85. delete _event;
  86. }
  87. }
  88. bool UdpSocket2ManagerWindows::Init(int32_t id,
  89. uint8_t& numOfWorkThreads) {
  90. CriticalSectionScoped cs(_pCrit);
  91. if ((_id != -1) || (_numOfWorkThreads != 0)) {
  92. assert(_id != -1);
  93. assert(_numOfWorkThreads != 0);
  94. return false;
  95. }
  96. _id = id;
  97. _numOfWorkThreads = numOfWorkThreads;
  98. return true;
  99. }
  100. int32_t UdpSocket2ManagerWindows::ChangeUniqueId(const int32_t id)
  101. {
  102. _id = id;
  103. return 0;
  104. }
  105. bool UdpSocket2ManagerWindows::Start()
  106. {
  107. WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
  108. "UdpSocket2ManagerWindows(%d)::Start()",_managerNumber);
  109. if(!_init)
  110. {
  111. StartWorkerThreads();
  112. }
  113. if(!_init)
  114. {
  115. return false;
  116. }
  117. _pCrit->Enter();
  118. // Start worker threads.
  119. _stopped = false;
  120. int32_t error = 0;
  121. ListItem* pItem = _workerThreadsList.First();
  122. UdpSocket2WorkerWindows* pWorker;
  123. while(pItem != NULL && !error)
  124. {
  125. pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
  126. if(!pWorker->Start())
  127. error = 1;
  128. pItem = _workerThreadsList.Next(pItem);
  129. }
  130. if(error)
  131. {
  132. WEBRTC_TRACE(
  133. kTraceError,
  134. kTraceTransport,
  135. _id,
  136. "UdpSocket2ManagerWindows(%d)::Start() error starting worker\
  137. threads",
  138. _managerNumber);
  139. _pCrit->Leave();
  140. return false;
  141. }
  142. _pCrit->Leave();
  143. return true;
  144. }
  145. bool UdpSocket2ManagerWindows::StartWorkerThreads()
  146. {
  147. if(!_init)
  148. {
  149. _pCrit->Enter();
  150. _ioCompletionHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,
  151. 0, 0);
  152. if(_ioCompletionHandle == NULL)
  153. {
  154. int32_t error = GetLastError();
  155. WEBRTC_TRACE(
  156. kTraceError,
  157. kTraceTransport,
  158. _id,
  159. "UdpSocket2ManagerWindows(%d)::StartWorkerThreads()"
  160. "_ioCompletioHandle == NULL: error:%d",
  161. _managerNumber,error);
  162. _pCrit->Leave();
  163. return false;
  164. }
  165. // Create worker threads.
  166. uint32_t i = 0;
  167. bool error = false;
  168. while(i < _numOfWorkThreads && !error)
  169. {
  170. UdpSocket2WorkerWindows* pWorker =
  171. new UdpSocket2WorkerWindows(_ioCompletionHandle);
  172. if(pWorker->Init() != 0)
  173. {
  174. error = true;
  175. delete pWorker;
  176. break;
  177. }
  178. _workerThreadsList.PushFront(pWorker);
  179. i++;
  180. }
  181. if(error)
  182. {
  183. WEBRTC_TRACE(
  184. kTraceError,
  185. kTraceTransport,
  186. _id,
  187. "UdpSocket2ManagerWindows(%d)::StartWorkerThreads() error "
  188. "creating work threads",
  189. _managerNumber);
  190. // Delete worker threads.
  191. ListItem* pItem = NULL;
  192. while((pItem = _workerThreadsList.First()) != NULL)
  193. {
  194. delete static_cast<UdpSocket2WorkerWindows*>(pItem->GetItem());
  195. _workerThreadsList.PopFront();
  196. }
  197. _pCrit->Leave();
  198. return false;
  199. }
  200. if(_ioContextPool.Init())
  201. {
  202. WEBRTC_TRACE(
  203. kTraceError,
  204. kTraceTransport,
  205. _id,
  206. "UdpSocket2ManagerWindows(%d)::StartWorkerThreads() error "
  207. "initiating _ioContextPool",
  208. _managerNumber);
  209. _pCrit->Leave();
  210. return false;
  211. }
  212. _init = true;
  213. WEBRTC_TRACE(
  214. kTraceDebug,
  215. kTraceTransport,
  216. _id,
  217. "UdpSocket2ManagerWindows::StartWorkerThreads %d number of work "
  218. "threads created and initialized",
  219. _numOfWorkThreads);
  220. _pCrit->Leave();
  221. }
  222. return true;
  223. }
  224. bool UdpSocket2ManagerWindows::Stop()
  225. {
  226. WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
  227. "UdpSocket2ManagerWindows(%d)::Stop()",_managerNumber);
  228. if(!_init)
  229. {
  230. return false;
  231. }
  232. _pCrit->Enter();
  233. _stopped = true;
  234. if(_numActiveSockets)
  235. {
  236. WEBRTC_TRACE(
  237. kTraceError,
  238. kTraceTransport,
  239. _id,
  240. "UdpSocket2ManagerWindows(%d)::Stop() there is still active\
  241. sockets",
  242. _managerNumber);
  243. _pCrit->Leave();
  244. return false;
  245. }
  246. // No active sockets. Stop all worker threads.
  247. bool result = StopWorkerThreads();
  248. _pCrit->Leave();
  249. return result;
  250. }
  251. bool UdpSocket2ManagerWindows::StopWorkerThreads()
  252. {
  253. int32_t error = 0;
  254. WEBRTC_TRACE(
  255. kTraceDebug,
  256. kTraceTransport,
  257. _id,
  258. "UdpSocket2ManagerWindows(%d)::StopWorkerThreads() Worker\
  259. threadsStoped, numActicve Sockets=%d",
  260. _managerNumber,
  261. _numActiveSockets);
  262. UdpSocket2WorkerWindows* pWorker;
  263. ListItem* pItem = _workerThreadsList.First();
  264. // Set worker threads to not alive so that they will stop calling
  265. // UdpSocket2WorkerWindows::Run().
  266. while(pItem != NULL)
  267. {
  268. pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
  269. pWorker->SetNotAlive();
  270. pItem = _workerThreadsList.Next(pItem);
  271. }
  272. // Release all threads waiting for GetQueuedCompletionStatus(..).
  273. if(_ioCompletionHandle)
  274. {
  275. uint32_t i = 0;
  276. for(i = 0; i < _workerThreadsList.GetSize(); i++)
  277. {
  278. PostQueuedCompletionStatus(_ioCompletionHandle, 0 ,0 , NULL);
  279. }
  280. }
  281. pItem = _workerThreadsList.First();
  282. while(pItem != NULL)
  283. {
  284. pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
  285. if(pWorker->Stop() == false)
  286. {
  287. error = -1;
  288. WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1,
  289. "failed to stop worker thread");
  290. }
  291. pItem = _workerThreadsList.Next(pItem);
  292. }
  293. if(error)
  294. {
  295. WEBRTC_TRACE(
  296. kTraceError,
  297. kTraceTransport,
  298. _id,
  299. "UdpSocket2ManagerWindows(%d)::StopWorkerThreads() error stopping\
  300. worker threads",
  301. _managerNumber);
  302. return false;
  303. }
  304. return true;
  305. }
  306. bool UdpSocket2ManagerWindows::AddSocketPrv(UdpSocket2Windows* s)
  307. {
  308. WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
  309. "UdpSocket2ManagerWindows(%d)::AddSocketPrv()",_managerNumber);
  310. if(!_init)
  311. {
  312. WEBRTC_TRACE(
  313. kTraceError,
  314. kTraceTransport,
  315. _id,
  316. "UdpSocket2ManagerWindows(%d)::AddSocketPrv() manager not\
  317. initialized",
  318. _managerNumber);
  319. return false;
  320. }
  321. _pCrit->Enter();
  322. if(s == NULL)
  323. {
  324. WEBRTC_TRACE(
  325. kTraceError,
  326. kTraceTransport,
  327. _id,
  328. "UdpSocket2ManagerWindows(%d)::AddSocketPrv() socket == NULL",
  329. _managerNumber);
  330. _pCrit->Leave();
  331. return false;
  332. }
  333. if(s->GetFd() == NULL || s->GetFd() == INVALID_SOCKET)
  334. {
  335. WEBRTC_TRACE(
  336. kTraceError,
  337. kTraceTransport,
  338. _id,
  339. "UdpSocket2ManagerWindows(%d)::AddSocketPrv() socket->GetFd() ==\
  340. %d",
  341. _managerNumber,
  342. (int32_t)s->GetFd());
  343. _pCrit->Leave();
  344. return false;
  345. }
  346. _ioCompletionHandle = CreateIoCompletionPort((HANDLE)s->GetFd(),
  347. _ioCompletionHandle,
  348. (ULONG_PTR)(s), 0);
  349. if(_ioCompletionHandle == NULL)
  350. {
  351. int32_t error = GetLastError();
  352. WEBRTC_TRACE(
  353. kTraceError,
  354. kTraceTransport,
  355. _id,
  356. "UdpSocket2ManagerWindows(%d)::AddSocketPrv() Error adding to IO\
  357. completion: %d",
  358. _managerNumber,
  359. error);
  360. _pCrit->Leave();
  361. return false;
  362. }
  363. _numActiveSockets++;
  364. _pCrit->Leave();
  365. return true;
  366. }
  367. bool UdpSocket2ManagerWindows::RemoveSocketPrv(UdpSocket2Windows* s)
  368. {
  369. if(!_init)
  370. {
  371. return false;
  372. }
  373. _pCrit->Enter();
  374. _numActiveSockets--;
  375. if(_numActiveSockets == 0)
  376. {
  377. _event->Set();
  378. }
  379. _pCrit->Leave();
  380. return true;
  381. }
  382. PerIoContext* UdpSocket2ManagerWindows::PopIoContext()
  383. {
  384. if(!_init)
  385. {
  386. return NULL;
  387. }
  388. PerIoContext* pIoC = NULL;
  389. if(!_stopped)
  390. {
  391. pIoC = _ioContextPool.PopIoContext();
  392. }else
  393. {
  394. WEBRTC_TRACE(
  395. kTraceError,
  396. kTraceTransport,
  397. _id,
  398. "UdpSocket2ManagerWindows(%d)::PopIoContext() Manager Not started",
  399. _managerNumber);
  400. }
  401. return pIoC;
  402. }
  403. int32_t UdpSocket2ManagerWindows::PushIoContext(PerIoContext* pIoContext)
  404. {
  405. return _ioContextPool.PushIoContext(pIoContext);
  406. }
  407. IoContextPool::IoContextPool()
  408. : _pListHead(NULL),
  409. _init(false),
  410. _size(0),
  411. _inUse(0)
  412. {
  413. }
  414. IoContextPool::~IoContextPool()
  415. {
  416. Free();
  417. assert(_size.Value() == 0);
  418. AlignedFree(_pListHead);
  419. }
  420. int32_t IoContextPool::Init(uint32_t /*increaseSize*/)
  421. {
  422. if(_init)
  423. {
  424. return 0;
  425. }
  426. _pListHead = (PSLIST_HEADER)AlignedMalloc(sizeof(SLIST_HEADER),
  427. MEMORY_ALLOCATION_ALIGNMENT);
  428. if(_pListHead == NULL)
  429. {
  430. return -1;
  431. }
  432. InitializeSListHead(_pListHead);
  433. _init = true;
  434. return 0;
  435. }
  436. PerIoContext* IoContextPool::PopIoContext()
  437. {
  438. if(!_init)
  439. {
  440. return NULL;
  441. }
  442. PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(_pListHead);
  443. if(pListEntry == NULL)
  444. {
  445. IoContextPoolItem* item = (IoContextPoolItem*)
  446. AlignedMalloc(
  447. sizeof(IoContextPoolItem),
  448. MEMORY_ALLOCATION_ALIGNMENT);
  449. if(item == NULL)
  450. {
  451. return NULL;
  452. }
  453. memset(&item->payload.ioContext,0,sizeof(PerIoContext));
  454. item->payload.base = item;
  455. pListEntry = &(item->itemEntry);
  456. ++_size;
  457. }
  458. ++_inUse;
  459. return &((IoContextPoolItem*)pListEntry)->payload.ioContext;
  460. }
  461. int32_t IoContextPool::PushIoContext(PerIoContext* pIoContext)
  462. {
  463. // TODO (hellner): Overlapped IO should be completed at this point. Perhaps
  464. // add an assert?
  465. const bool overlappedIOCompleted = HasOverlappedIoCompleted(
  466. (LPOVERLAPPED)pIoContext);
  467. IoContextPoolItem* item = ((IoContextPoolItemPayload*)pIoContext)->base;
  468. const int32_t usedItems = --_inUse;
  469. const int32_t totalItems = _size.Value();
  470. const int32_t freeItems = totalItems - usedItems;
  471. if(freeItems < 0)
  472. {
  473. assert(false);
  474. AlignedFree(item);
  475. return -1;
  476. }
  477. if((freeItems >= totalItems>>1) &&
  478. overlappedIOCompleted)
  479. {
  480. AlignedFree(item);
  481. --_size;
  482. return 0;
  483. }
  484. InterlockedPushEntrySList(_pListHead, &(item->itemEntry));
  485. return 0;
  486. }
  487. int32_t IoContextPool::Free()
  488. {
  489. if(!_init)
  490. {
  491. return 0;
  492. }
  493. int32_t itemsFreed = 0;
  494. PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(_pListHead);
  495. while(pListEntry != NULL)
  496. {
  497. IoContextPoolItem* item = ((IoContextPoolItem*)pListEntry);
  498. AlignedFree(item);
  499. --_size;
  500. itemsFreed++;
  501. pListEntry = InterlockedPopEntrySList(_pListHead);
  502. }
  503. return itemsFreed;
  504. }
  505. int32_t UdpSocket2WorkerWindows::_numOfWorkers = 0;
  506. UdpSocket2WorkerWindows::UdpSocket2WorkerWindows(HANDLE ioCompletionHandle)
  507. : _ioCompletionHandle(ioCompletionHandle),
  508. _pThread(NULL),
  509. _init(false)
  510. {
  511. _workerNumber = _numOfWorkers++;
  512. WEBRTC_TRACE(kTraceMemory, kTraceTransport, -1,
  513. "UdpSocket2WorkerWindows created");
  514. }
  515. UdpSocket2WorkerWindows::~UdpSocket2WorkerWindows()
  516. {
  517. if(_pThread)
  518. {
  519. delete _pThread;
  520. }
  521. WEBRTC_TRACE(kTraceMemory, kTraceTransport, -1,
  522. "UdpSocket2WorkerWindows deleted");
  523. }
  524. bool UdpSocket2WorkerWindows::Start()
  525. {
  526. unsigned int id = 0;
  527. WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
  528. "Start UdpSocket2WorkerWindows");
  529. return _pThread->Start(id);
  530. }
  531. bool UdpSocket2WorkerWindows::Stop()
  532. {
  533. WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
  534. "Stop UdpSocket2WorkerWindows");
  535. return _pThread->Stop();
  536. }
  537. void UdpSocket2WorkerWindows::SetNotAlive()
  538. {
  539. WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
  540. "SetNotAlive UdpSocket2WorkerWindows");
  541. _pThread->SetNotAlive();
  542. }
  543. int32_t UdpSocket2WorkerWindows::Init()
  544. {
  545. if(!_init)
  546. {
  547. const char* threadName = "UdpSocket2ManagerWindows_thread";
  548. _pThread = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
  549. threadName);
  550. if(_pThread == NULL)
  551. {
  552. WEBRTC_TRACE(
  553. kTraceError,
  554. kTraceTransport,
  555. -1,
  556. "UdpSocket2WorkerWindows(%d)::Init(), error creating thread!",
  557. _workerNumber);
  558. return -1;
  559. }
  560. _init = true;
  561. }
  562. return 0;
  563. }
  564. bool UdpSocket2WorkerWindows::Run(ThreadObj obj)
  565. {
  566. UdpSocket2WorkerWindows* pWorker =
  567. static_cast<UdpSocket2WorkerWindows*>(obj);
  568. return pWorker->Process();
  569. }
  570. // Process should always return true. Stopping the worker threads is done in
  571. // the UdpSocket2ManagerWindows::StopWorkerThreads() function.
  572. bool UdpSocket2WorkerWindows::Process()
  573. {
  574. int32_t success = 0;
  575. DWORD ioSize = 0;
  576. UdpSocket2Windows* pSocket = NULL;
  577. PerIoContext* pIOContext = 0;
  578. OVERLAPPED* pOverlapped = 0;
  579. success = GetQueuedCompletionStatus(_ioCompletionHandle,
  580. &ioSize,
  581. (ULONG_PTR*)&pSocket, &pOverlapped, 200);
  582. uint32_t error = 0;
  583. if(!success)
  584. {
  585. error = GetLastError();
  586. if(error == WAIT_TIMEOUT)
  587. {
  588. return true;
  589. }
  590. // This may happen if e.g. PostQueuedCompletionStatus() has been called.
  591. // The IO context still needs to be reclaimed or re-used which is done
  592. // in UdpSocket2Windows::IOCompleted(..).
  593. }
  594. if(pSocket == NULL)
  595. {
  596. WEBRTC_TRACE(
  597. kTraceDebug,
  598. kTraceTransport,
  599. -1,
  600. "UdpSocket2WorkerWindows(%d)::Process(), pSocket == 0, end thread",
  601. _workerNumber);
  602. return true;
  603. }
  604. pIOContext = (PerIoContext*)pOverlapped;
  605. pSocket->IOCompleted(pIOContext,ioSize,error);
  606. return true;
  607. }
  608. } // namespace test
  609. } // namespace webrtc