/webrtc/test/channel_transport/udp_socket2_manager_win.cc
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
- /*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
- #include "webrtc/test/channel_transport/udp_socket2_manager_win.h"
- #include <assert.h>
- #include <stdio.h>
- #include "webrtc/system_wrappers/interface/aligned_malloc.h"
- #include "webrtc/test/channel_transport/udp_socket2_win.h"
- namespace webrtc {
- namespace test {
- uint32_t UdpSocket2ManagerWindows::_numOfActiveManagers = 0;
- bool UdpSocket2ManagerWindows::_wsaInit = false;
- UdpSocket2ManagerWindows::UdpSocket2ManagerWindows()
- : UdpSocketManager(),
- _id(-1),
- _stopped(false),
- _init(false),
- _pCrit(CriticalSectionWrapper::CreateCriticalSection()),
- _ioCompletionHandle(NULL),
- _numActiveSockets(0),
- _event(EventWrapper::Create())
- {
- _managerNumber = _numOfActiveManagers++;
- if(_numOfActiveManagers == 1)
- {
- WORD wVersionRequested = MAKEWORD(2, 2);
- WSADATA wsaData;
- _wsaInit = WSAStartup(wVersionRequested, &wsaData) == 0;
- // TODO (hellner): seems safer to use RAII for this. E.g. what happens
- // if a UdpSocket2ManagerWindows() created and destroyed
- // without being initialized.
- }
- }
- UdpSocket2ManagerWindows::~UdpSocket2ManagerWindows()
- {
- WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
- "UdpSocket2ManagerWindows(%d)::~UdpSocket2ManagerWindows()",
- _managerNumber);
- if(_init)
- {
- _pCrit->Enter();
- if(_numActiveSockets)
- {
- _pCrit->Leave();
- _event->Wait(INFINITE);
- }
- else
- {
- _pCrit->Leave();
- }
- StopWorkerThreads();
- // All threads are stopped. Safe to delete them.
- ListItem* pItem = NULL;
- while((pItem = _workerThreadsList.First()) != NULL)
- {
- delete static_cast<UdpSocket2WorkerWindows*>(pItem->GetItem());
- _workerThreadsList.PopFront();
- }
- _ioContextPool.Free();
- _numOfActiveManagers--;
- if(_ioCompletionHandle)
- {
- CloseHandle(_ioCompletionHandle);
- }
- if (_numOfActiveManagers == 0)
- {
- if(_wsaInit)
- {
- WSACleanup();
- }
- }
- }
- if(_pCrit)
- {
- delete _pCrit;
- }
- if(_event)
- {
- delete _event;
- }
- }
- bool UdpSocket2ManagerWindows::Init(int32_t id,
- uint8_t& numOfWorkThreads) {
- CriticalSectionScoped cs(_pCrit);
- if ((_id != -1) || (_numOfWorkThreads != 0)) {
- assert(_id != -1);
- assert(_numOfWorkThreads != 0);
- return false;
- }
- _id = id;
- _numOfWorkThreads = numOfWorkThreads;
- return true;
- }
- int32_t UdpSocket2ManagerWindows::ChangeUniqueId(const int32_t id)
- {
- _id = id;
- return 0;
- }
- bool UdpSocket2ManagerWindows::Start()
- {
- WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
- "UdpSocket2ManagerWindows(%d)::Start()",_managerNumber);
- if(!_init)
- {
- StartWorkerThreads();
- }
- if(!_init)
- {
- return false;
- }
- _pCrit->Enter();
- // Start worker threads.
- _stopped = false;
- int32_t error = 0;
- ListItem* pItem = _workerThreadsList.First();
- UdpSocket2WorkerWindows* pWorker;
- while(pItem != NULL && !error)
- {
- pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
- if(!pWorker->Start())
- error = 1;
- pItem = _workerThreadsList.Next(pItem);
- }
- if(error)
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::Start() error starting worker\
- threads",
- _managerNumber);
- _pCrit->Leave();
- return false;
- }
- _pCrit->Leave();
- return true;
- }
- bool UdpSocket2ManagerWindows::StartWorkerThreads()
- {
- if(!_init)
- {
- _pCrit->Enter();
- _ioCompletionHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,
- 0, 0);
- if(_ioCompletionHandle == NULL)
- {
- int32_t error = GetLastError();
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::StartWorkerThreads()"
- "_ioCompletioHandle == NULL: error:%d",
- _managerNumber,error);
- _pCrit->Leave();
- return false;
- }
- // Create worker threads.
- uint32_t i = 0;
- bool error = false;
- while(i < _numOfWorkThreads && !error)
- {
- UdpSocket2WorkerWindows* pWorker =
- new UdpSocket2WorkerWindows(_ioCompletionHandle);
- if(pWorker->Init() != 0)
- {
- error = true;
- delete pWorker;
- break;
- }
- _workerThreadsList.PushFront(pWorker);
- i++;
- }
- if(error)
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::StartWorkerThreads() error "
- "creating work threads",
- _managerNumber);
- // Delete worker threads.
- ListItem* pItem = NULL;
- while((pItem = _workerThreadsList.First()) != NULL)
- {
- delete static_cast<UdpSocket2WorkerWindows*>(pItem->GetItem());
- _workerThreadsList.PopFront();
- }
- _pCrit->Leave();
- return false;
- }
- if(_ioContextPool.Init())
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::StartWorkerThreads() error "
- "initiating _ioContextPool",
- _managerNumber);
- _pCrit->Leave();
- return false;
- }
- _init = true;
- WEBRTC_TRACE(
- kTraceDebug,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows::StartWorkerThreads %d number of work "
- "threads created and initialized",
- _numOfWorkThreads);
- _pCrit->Leave();
- }
- return true;
- }
- bool UdpSocket2ManagerWindows::Stop()
- {
- WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
- "UdpSocket2ManagerWindows(%d)::Stop()",_managerNumber);
- if(!_init)
- {
- return false;
- }
- _pCrit->Enter();
- _stopped = true;
- if(_numActiveSockets)
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::Stop() there is still active\
- sockets",
- _managerNumber);
- _pCrit->Leave();
- return false;
- }
- // No active sockets. Stop all worker threads.
- bool result = StopWorkerThreads();
- _pCrit->Leave();
- return result;
- }
- bool UdpSocket2ManagerWindows::StopWorkerThreads()
- {
- int32_t error = 0;
- WEBRTC_TRACE(
- kTraceDebug,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::StopWorkerThreads() Worker\
- threadsStoped, numActicve Sockets=%d",
- _managerNumber,
- _numActiveSockets);
- UdpSocket2WorkerWindows* pWorker;
- ListItem* pItem = _workerThreadsList.First();
- // Set worker threads to not alive so that they will stop calling
- // UdpSocket2WorkerWindows::Run().
- while(pItem != NULL)
- {
- pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
- pWorker->SetNotAlive();
- pItem = _workerThreadsList.Next(pItem);
- }
- // Release all threads waiting for GetQueuedCompletionStatus(..).
- if(_ioCompletionHandle)
- {
- uint32_t i = 0;
- for(i = 0; i < _workerThreadsList.GetSize(); i++)
- {
- PostQueuedCompletionStatus(_ioCompletionHandle, 0 ,0 , NULL);
- }
- }
- pItem = _workerThreadsList.First();
- while(pItem != NULL)
- {
- pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
- if(pWorker->Stop() == false)
- {
- error = -1;
- WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1,
- "failed to stop worker thread");
- }
- pItem = _workerThreadsList.Next(pItem);
- }
- if(error)
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::StopWorkerThreads() error stopping\
- worker threads",
- _managerNumber);
- return false;
- }
- return true;
- }
- bool UdpSocket2ManagerWindows::AddSocketPrv(UdpSocket2Windows* s)
- {
- WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
- "UdpSocket2ManagerWindows(%d)::AddSocketPrv()",_managerNumber);
- if(!_init)
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::AddSocketPrv() manager not\
- initialized",
- _managerNumber);
- return false;
- }
- _pCrit->Enter();
- if(s == NULL)
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::AddSocketPrv() socket == NULL",
- _managerNumber);
- _pCrit->Leave();
- return false;
- }
- if(s->GetFd() == NULL || s->GetFd() == INVALID_SOCKET)
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::AddSocketPrv() socket->GetFd() ==\
- %d",
- _managerNumber,
- (int32_t)s->GetFd());
- _pCrit->Leave();
- return false;
- }
- _ioCompletionHandle = CreateIoCompletionPort((HANDLE)s->GetFd(),
- _ioCompletionHandle,
- (ULONG_PTR)(s), 0);
- if(_ioCompletionHandle == NULL)
- {
- int32_t error = GetLastError();
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::AddSocketPrv() Error adding to IO\
- completion: %d",
- _managerNumber,
- error);
- _pCrit->Leave();
- return false;
- }
- _numActiveSockets++;
- _pCrit->Leave();
- return true;
- }
- bool UdpSocket2ManagerWindows::RemoveSocketPrv(UdpSocket2Windows* s)
- {
- if(!_init)
- {
- return false;
- }
- _pCrit->Enter();
- _numActiveSockets--;
- if(_numActiveSockets == 0)
- {
- _event->Set();
- }
- _pCrit->Leave();
- return true;
- }
- PerIoContext* UdpSocket2ManagerWindows::PopIoContext()
- {
- if(!_init)
- {
- return NULL;
- }
- PerIoContext* pIoC = NULL;
- if(!_stopped)
- {
- pIoC = _ioContextPool.PopIoContext();
- }else
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- _id,
- "UdpSocket2ManagerWindows(%d)::PopIoContext() Manager Not started",
- _managerNumber);
- }
- return pIoC;
- }
- int32_t UdpSocket2ManagerWindows::PushIoContext(PerIoContext* pIoContext)
- {
- return _ioContextPool.PushIoContext(pIoContext);
- }
- IoContextPool::IoContextPool()
- : _pListHead(NULL),
- _init(false),
- _size(0),
- _inUse(0)
- {
- }
- IoContextPool::~IoContextPool()
- {
- Free();
- assert(_size.Value() == 0);
- AlignedFree(_pListHead);
- }
- int32_t IoContextPool::Init(uint32_t /*increaseSize*/)
- {
- if(_init)
- {
- return 0;
- }
- _pListHead = (PSLIST_HEADER)AlignedMalloc(sizeof(SLIST_HEADER),
- MEMORY_ALLOCATION_ALIGNMENT);
- if(_pListHead == NULL)
- {
- return -1;
- }
- InitializeSListHead(_pListHead);
- _init = true;
- return 0;
- }
- PerIoContext* IoContextPool::PopIoContext()
- {
- if(!_init)
- {
- return NULL;
- }
- PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(_pListHead);
- if(pListEntry == NULL)
- {
- IoContextPoolItem* item = (IoContextPoolItem*)
- AlignedMalloc(
- sizeof(IoContextPoolItem),
- MEMORY_ALLOCATION_ALIGNMENT);
- if(item == NULL)
- {
- return NULL;
- }
- memset(&item->payload.ioContext,0,sizeof(PerIoContext));
- item->payload.base = item;
- pListEntry = &(item->itemEntry);
- ++_size;
- }
- ++_inUse;
- return &((IoContextPoolItem*)pListEntry)->payload.ioContext;
- }
- int32_t IoContextPool::PushIoContext(PerIoContext* pIoContext)
- {
- // TODO (hellner): Overlapped IO should be completed at this point. Perhaps
- // add an assert?
- const bool overlappedIOCompleted = HasOverlappedIoCompleted(
- (LPOVERLAPPED)pIoContext);
- IoContextPoolItem* item = ((IoContextPoolItemPayload*)pIoContext)->base;
- const int32_t usedItems = --_inUse;
- const int32_t totalItems = _size.Value();
- const int32_t freeItems = totalItems - usedItems;
- if(freeItems < 0)
- {
- assert(false);
- AlignedFree(item);
- return -1;
- }
- if((freeItems >= totalItems>>1) &&
- overlappedIOCompleted)
- {
- AlignedFree(item);
- --_size;
- return 0;
- }
- InterlockedPushEntrySList(_pListHead, &(item->itemEntry));
- return 0;
- }
- int32_t IoContextPool::Free()
- {
- if(!_init)
- {
- return 0;
- }
- int32_t itemsFreed = 0;
- PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(_pListHead);
- while(pListEntry != NULL)
- {
- IoContextPoolItem* item = ((IoContextPoolItem*)pListEntry);
- AlignedFree(item);
- --_size;
- itemsFreed++;
- pListEntry = InterlockedPopEntrySList(_pListHead);
- }
- return itemsFreed;
- }
- int32_t UdpSocket2WorkerWindows::_numOfWorkers = 0;
- UdpSocket2WorkerWindows::UdpSocket2WorkerWindows(HANDLE ioCompletionHandle)
- : _ioCompletionHandle(ioCompletionHandle),
- _pThread(NULL),
- _init(false)
- {
- _workerNumber = _numOfWorkers++;
- WEBRTC_TRACE(kTraceMemory, kTraceTransport, -1,
- "UdpSocket2WorkerWindows created");
- }
- UdpSocket2WorkerWindows::~UdpSocket2WorkerWindows()
- {
- if(_pThread)
- {
- delete _pThread;
- }
- WEBRTC_TRACE(kTraceMemory, kTraceTransport, -1,
- "UdpSocket2WorkerWindows deleted");
- }
- bool UdpSocket2WorkerWindows::Start()
- {
- unsigned int id = 0;
- WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
- "Start UdpSocket2WorkerWindows");
- return _pThread->Start(id);
- }
- bool UdpSocket2WorkerWindows::Stop()
- {
- WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
- "Stop UdpSocket2WorkerWindows");
- return _pThread->Stop();
- }
- void UdpSocket2WorkerWindows::SetNotAlive()
- {
- WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
- "SetNotAlive UdpSocket2WorkerWindows");
- _pThread->SetNotAlive();
- }
- int32_t UdpSocket2WorkerWindows::Init()
- {
- if(!_init)
- {
- const char* threadName = "UdpSocket2ManagerWindows_thread";
- _pThread = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
- threadName);
- if(_pThread == NULL)
- {
- WEBRTC_TRACE(
- kTraceError,
- kTraceTransport,
- -1,
- "UdpSocket2WorkerWindows(%d)::Init(), error creating thread!",
- _workerNumber);
- return -1;
- }
- _init = true;
- }
- return 0;
- }
- bool UdpSocket2WorkerWindows::Run(ThreadObj obj)
- {
- UdpSocket2WorkerWindows* pWorker =
- static_cast<UdpSocket2WorkerWindows*>(obj);
- return pWorker->Process();
- }
- // Process should always return true. Stopping the worker threads is done in
- // the UdpSocket2ManagerWindows::StopWorkerThreads() function.
- bool UdpSocket2WorkerWindows::Process()
- {
- int32_t success = 0;
- DWORD ioSize = 0;
- UdpSocket2Windows* pSocket = NULL;
- PerIoContext* pIOContext = 0;
- OVERLAPPED* pOverlapped = 0;
- success = GetQueuedCompletionStatus(_ioCompletionHandle,
- &ioSize,
- (ULONG_PTR*)&pSocket, &pOverlapped, 200);
- uint32_t error = 0;
- if(!success)
- {
- error = GetLastError();
- if(error == WAIT_TIMEOUT)
- {
- return true;
- }
- // This may happen if e.g. PostQueuedCompletionStatus() has been called.
- // The IO context still needs to be reclaimed or re-used which is done
- // in UdpSocket2Windows::IOCompleted(..).
- }
- if(pSocket == NULL)
- {
- WEBRTC_TRACE(
- kTraceDebug,
- kTraceTransport,
- -1,
- "UdpSocket2WorkerWindows(%d)::Process(), pSocket == 0, end thread",
- _workerNumber);
- return true;
- }
- pIOContext = (PerIoContext*)pOverlapped;
- pSocket->IOCompleted(pIOContext,ioSize,error);
- return true;
- }
- } // namespace test
- } // namespace webrtc