From 0c5f4cdc1a0c7a5dd508b11d3d908254804399c8 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Tue, 8 Jun 2021 18:10:51 +0800 Subject: [PATCH] Implement NLNET sleepUntilDataAvailable for Win32 build --- nel/include/nel/net/buf_net_base.h | 15 +++++++- nel/include/nel/net/unified_network.h | 6 ++- nel/src/net/buf_net_base.cpp | 14 +++++-- nel/src/net/unified_network.cpp | 54 +++++++++++++++++++++------ 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/nel/include/nel/net/buf_net_base.h b/nel/include/nel/net/buf_net_base.h index 26e35a5ce..88e7aad66 100644 --- a/nel/include/nel/net/buf_net_base.h +++ b/nel/include/nel/net/buf_net_base.h @@ -56,6 +56,10 @@ extern uint32 NbNetworkTask; enum TPipeWay { PipeRead, PipeWrite }; #endif +#ifdef NL_OS_WINDOWS +typedef void *HANDLE; +#endif + /** * Layer 1 @@ -78,7 +82,7 @@ public: /// Destructor virtual ~CBufNetBase(); -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) /** Init the pipe for data available with an external pipe. * Call it only if you set initPipeForDataAvailable to false in the constructor. * Then don't call sleepUntilDataAvailable() but use select() on the pipe. @@ -89,6 +93,11 @@ public: _DataAvailablePipeHandle[PipeRead] = twoPipeHandles[PipeRead]; _DataAvailablePipeHandle[PipeWrite] = twoPipeHandles[PipeWrite]; } +#elif defined(NL_OS_WINDOWS) + void setExternalPipeForDataAvailable(HANDLE eventHandle) + { + _DataAvailableHandle = eventHandle; + } #endif /// Sets callback for detecting a disconnection (or NULL to disable callback) @@ -201,9 +210,11 @@ protected: /// Return _DataAvailable bool dataAvailableFlag() const { return _DataAvailable; } -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) /// Pipe to select() on data available int _DataAvailablePipeHandle [2]; +#elif defined(NL_OS_WINDOWS) + HANDLE _DataAvailableHandle; #endif private: diff --git a/nel/include/nel/net/unified_network.h b/nel/include/nel/net/unified_network.h index 094ff7390..a40037e06 100644 --- a/nel/include/nel/net/unified_network.h +++ b/nel/include/nel/net/unified_network.h @@ -638,7 +638,7 @@ protected: /// Auto-reconnect void autoReconnect( CUnifiedConnection &uc, uint connectionIndex ); -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) || defined(NL_OS_WINDOWS) /// Sleep (implemented by select()) void sleepUntilDataAvailable( NLMISC::TTime msecMax ); #endif @@ -700,9 +700,11 @@ private: /// for each services, which network to take std::vector _DefaultNetwork; -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) /// Pipe to select() on data available (shared among all connections) int _MainDataAvailablePipe [2]; +#elif defined(NL_OS_WINDOWS) + HANDLE _MainDataAvailableHandle; #endif /// Service id of the running service diff --git a/nel/src/net/buf_net_base.cpp b/nel/src/net/buf_net_base.cpp index cc6a397aa..eefc22cfc 100644 --- a/nel/src/net/buf_net_base.cpp +++ b/nel/src/net/buf_net_base.cpp @@ -57,13 +57,15 @@ CBufNetBase::CBufNetBase() : #ifdef MUTEX_DEBUG initAcquireTimeMap(); #endif -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) _IsDataAvailablePipeSelfManaged = isDataAvailablePipeSelfManaged; if ( _IsDataAvailablePipeSelfManaged ) { if ( ::pipe( _DataAvailablePipeHandle ) != 0 ) nlwarning( "Unable to create D.A. pipe" ); } +#elif defined(NL_OS_WINDOWS) + _DataAvailableHandle = NULL; #endif } @@ -99,7 +101,7 @@ void CBufNetBase::pushMessageIntoReceiveQueue( const std::vector& buffer //mbsize = recvfifo.value().size() / 1048576; setDataAvailableFlag( true ); } -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) // Wake-up main thread (outside the critical section of CFifoAccessor, to allow main thread to be // read the fifo; if the main thread sees the Data Available flag is true but the pipe not written // yet, it will block on read()). @@ -109,6 +111,9 @@ void CBufNetBase::pushMessageIntoReceiveQueue( const std::vector& buffer nlwarning( "LNETL1: Write pipe failed in pushMessageIntoReceiveQueue" ); } //nldebug( "Pipe: 1 byte written (%p)", this ); +#elif defined(NL_OS_WINDOWS) + if (_DataAvailableHandle) + SetEvent(_DataAvailableHandle); #endif //nldebug( "BNB: Released." ); //if ( mbsize > 1 ) @@ -131,7 +136,7 @@ void CBufNetBase::pushMessageIntoReceiveQueue( const uint8 *buffer, uint32 size //nldebug( "BNB: Pushed, releasing the receive queue..." ); //mbsize = recvfifo.value().size() / 1048576; setDataAvailableFlag( true ); -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) // Wake-up main thread uint8 b=0; if ( write( _DataAvailablePipeHandle[PipeWrite], &b, 1 ) == -1 ) @@ -139,6 +144,9 @@ void CBufNetBase::pushMessageIntoReceiveQueue( const uint8 *buffer, uint32 size nlwarning( "LNETL1: Write pipe failed in pushMessageIntoReceiveQueue" ); } nldebug( "Pipe: 1 byte written" ); +#elif defined(NL_OS_WINDOWS) + if (_DataAvailableHandle) + SetEvent(_DataAvailableHandle); #endif } //nldebug( "BNB: Released." ); diff --git a/nel/src/net/unified_network.cpp b/nel/src/net/unified_network.cpp index 0ac8b1c21..d624fcff0 100644 --- a/nel/src/net/unified_network.cpp +++ b/nel/src/net/unified_network.cpp @@ -45,8 +45,8 @@ uint32 TotalCallbackCalled = 0; uint32 TimeInCallback =0; -#ifdef NL_OS_UNIX -/// Yield method (Unix only) +#if defined(NL_OS_UNIX) || defined(NL_OS_WINDOWS) +/// Yield method CVariable UseYieldMethod("nel", "UseYieldMethod", "0=select 1=usleep 2=nanosleep 3=sched_yield 4=none", 0, 0, true ); #endif @@ -564,11 +564,15 @@ bool CUnifiedNetwork::init(const CInetAddress *addr, CCallbackNetBase::TRecordin port = CNamingClient::queryServicePort (); } -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) /// Init the main pipe to select() on data available if ( ::pipe( _MainDataAvailablePipe ) != 0 ) nlwarning( "Unable to create main D.A. pipe" ); //nldebug( "Pipe: created" ); +#elif defined(NL_OS_WINDOWS) + _MainDataAvailableHandle = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!_MainDataAvailableHandle) + nlwarning("Unable to create main D.A. event"); #endif // setup the server callback only if server port != 0, otherwise there's no server callback @@ -578,9 +582,11 @@ bool CUnifiedNetwork::init(const CInetAddress *addr, CCallbackNetBase::TRecordin { nlassert (_CbServer == 0); _CbServer = new CCallbackServer( CCallbackNetBase::Off, "", true, false ); // don't init one pipe per connection -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) _CbServer->setExternalPipeForDataAvailable( _MainDataAvailablePipe ); // the main pipe is shared for all connections //nldebug( "Pipe: set (server %p)", _CbServer ); +#elif defined(NL_OS_WINDOWS) + _CbServer->setExternalPipeForDataAvailable(_MainDataAvailableHandle); #endif bool retry = false; do @@ -754,9 +760,15 @@ void CUnifiedNetwork::release(bool mustFlushSendQueues, const std::vector // Create a new connection with the service, setup callback and connect CCallbackClient *cbc = new CCallbackClient( CCallbackNetBase::Off, "", true, false ); // don't init one pipe per connection -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) cbc->setExternalPipeForDataAvailable( _MainDataAvailablePipe ); // the main pipe is shared for all connections //nldebug( "Pipe: set (client %p)", cbc ); +#elif defined(NL_OS_WINDOWS) + cbc->setExternalPipeForDataAvailable(_MainDataAvailableHandle); #endif cbc->setDisconnectionCallback(uncbDisconnection, NULL); cbc->setDefaultCallback(uncbMsgProcessing); @@ -1147,7 +1161,7 @@ void CUnifiedNetwork::update(TTime timeout) t0 = currentTime - (timeout - remainingTime); } -#ifdef NL_OS_UNIX +#if defined(NL_OS_UNIX) // Sleep until the time expires or we receive a message H_BEFORE(L5UpdateSleep); switch ( UseYieldMethod.get() ) @@ -1159,6 +1173,18 @@ void CUnifiedNetwork::update(TTime timeout) default: break; // don't sleep at all, makes all slow! } H_AFTER(L5UpdateSleep); +#elif defined(NL_OS_WINDOWS) + // Sleep until the time expires or we receive a message + H_BEFORE(L5UpdateSleep); + switch (UseYieldMethod.get()) + { + case 0: sleepUntilDataAvailable(remainingTime); break; // accurate sleep + case 1: nlSleep(1); break; + case 2: nlSleep(1); break; + case 3: SwitchToThread(); break; + default: break; // don't sleep at all, makes all slow! + } + H_AFTER(L5UpdateSleep); #else // Enable windows multithreading before rescanning all connections H_TIME(L5UpdateSleep, nlSleep(1);); // 0 (yield) would be too harmful to other applications @@ -1222,10 +1248,7 @@ void CUnifiedNetwork::autoReconnect( CUnifiedConnection &uc, uint connectionInde } } -#ifdef NL_OS_UNIX -/* - * - */ +#if defined(NL_OS_UNIX) void CUnifiedNetwork::sleepUntilDataAvailable( TTime msecMax ) { // Prevent looping infinitely if an erroneous time was provided @@ -1249,6 +1272,15 @@ void CUnifiedNetwork::sleepUntilDataAvailable( TTime msecMax ) nlwarning( "HNETL5: Select failed in sleepUntilDataAvailable"); //nldebug( "Slept %u ms", (uint)(CTime::getLocalTime()-before) ); } +#elif defined(NL_OS_WINDOWS) +void CUnifiedNetwork::sleepUntilDataAvailable(TTime msecMax) +{ + if (msecMax > 999) + msecMax = 999; + + nlassert(_MainDataAvailableHandle); + WaitForSingleObject(_MainDataAvailableHandle, msecMax); +} #endif