LCOV - code coverage report
Current view: top level - lunchbox - requestHandler.cpp (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 132 141 93.6 %
Date: 2018-10-03 05:33:11 Functions: 25 25 100.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2017, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or modify it under
       5             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       6             :  * by the Free Software Foundation.
       7             :  *
       8             :  * This library is distributed in the hope that it will be useful, but WITHOUT
       9             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      10             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      11             :  * details.
      12             :  *
      13             :  * You should have received a copy of the GNU Lesser General Public License
      14             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      15             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      16             :  */
      17             : 
      18             : #include "requestHandler.h"
      19             : 
      20             : #include "scopedMutex.h"
      21             : 
      22             : #include <lunchbox/debug.h>
      23             : #include <lunchbox/spinLock.h>
      24             : 
      25             : #include <list>
      26             : #include <unordered_map>
      27             : 
      28             : namespace lunchbox
      29             : {
      30             : //! @cond IGNORE
      31             : namespace
      32             : {
      33             : struct Record
      34             : {
      35           3 :     Record() { lock.lock(); }
      36           3 :     ~Record() {}
      37             :     std::timed_mutex lock;
      38             :     void* data;
      39             : 
      40             :     union Result {
      41             :         void* rPointer;
      42             :         uint32_t rUint32;
      43             :         bool rBool;
      44             :         struct
      45             :         {
      46             :             uint64_t low;
      47             :             uint64_t high;
      48             :         } rUint128;
      49             :     } result;
      50             : };
      51             : typedef std::unordered_map<uint32_t, Record*> RecordHash;
      52             : typedef RecordHash::const_iterator RecordHashCIter;
      53             : }
      54             : 
      55             : namespace detail
      56             : {
      57           1 : class RequestHandler
      58             : {
      59             : public:
      60           1 :     RequestHandler()
      61           1 :         : requestID(1)
      62             :     {
      63           1 :     }
      64             : 
      65           7 :     uint32_t registerRequest(void* data)
      66             :     {
      67          14 :         ScopedFastWrite mutex(lock);
      68             : 
      69             :         Record* request;
      70           7 :         if (freeRecords.empty())
      71           3 :             request = new Record;
      72             :         else
      73             :         {
      74           4 :             request = freeRecords.front();
      75           4 :             freeRecords.pop_front();
      76             :         }
      77             : 
      78           7 :         request->data = data;
      79           7 :         requestID = (requestID + 1) % LB_MAX_UINT32;
      80           7 :         requests[requestID] = request;
      81          14 :         return requestID;
      82             :     }
      83             : 
      84           7 :     bool waitRequest(const uint32_t requestID_, Record::Result& result,
      85             :                      const uint32_t timeout)
      86             :     {
      87           7 :         result.rUint128.low = 0;
      88           7 :         result.rUint128.high = 0;
      89           7 :         Record* request = 0;
      90             :         {
      91          14 :             ScopedFastWrite mutex(lock);
      92           7 :             RecordHashCIter i = requests.find(requestID_);
      93           7 :             if (i == requests.end())
      94           0 :                 return false;
      95             : 
      96           7 :             request = i->second;
      97             :         }
      98             : 
      99           7 :         if (timeout == LB_TIMEOUT_INDEFINITE) // opt
     100             :         {
     101           6 :             request->lock.lock();
     102           6 :             result = request->result;
     103           6 :             unregisterRequest(requestID_);
     104           6 :             return true;
     105             :         }
     106             : 
     107             :         const bool requestServed =
     108           1 :             request->lock.try_lock_for(std::chrono::milliseconds(timeout));
     109           1 :         if (requestServed)
     110             :         {
     111           0 :             result = request->result;
     112           0 :             unregisterRequest(requestID_);
     113             :         }
     114             : 
     115           1 :         return requestServed;
     116             :     }
     117             : 
     118           7 :     void unregisterRequest(const uint32_t requestID_)
     119             :     {
     120          14 :         ScopedFastWrite mutex(lock);
     121           7 :         RecordHash::iterator i = requests.find(requestID_);
     122           7 :         if (i == requests.end())
     123           0 :             return;
     124             : 
     125           7 :         Record* request = i->second;
     126           7 :         requests.erase(i);
     127           7 :         freeRecords.push_front(request);
     128             :     }
     129             : 
     130             :     mutable lunchbox::SpinLock lock;
     131             :     uint32_t requestID;
     132             :     RecordHash requests;
     133             :     std::list<Record*> freeRecords;
     134             : };
     135             : }
     136             : // @endcond
     137             : 
     138           1 : RequestHandler::RequestHandler()
     139           1 :     : _impl(new detail::RequestHandler)
     140             : {
     141           1 : }
     142             : 
     143           5 : RequestHandler::~RequestHandler()
     144             : {
     145           7 :     while (!_impl->freeRecords.empty())
     146             :     {
     147           3 :         Record* request = _impl->freeRecords.front();
     148           3 :         _impl->freeRecords.pop_front();
     149           3 :         delete request;
     150             :     }
     151           1 :     delete _impl;
     152           1 : }
     153             : 
     154           7 : uint32_t RequestHandler::_register(void* data)
     155             : {
     156           7 :     return _impl->registerRequest(data);
     157             : }
     158             : 
     159           1 : void RequestHandler::unregisterRequest(const uint32_t requestID)
     160             : {
     161           1 :     _impl->unregisterRequest(requestID);
     162           1 : }
     163             : 
     164           3 : bool RequestHandler::waitRequest(const uint32_t requestID, void*& rPointer,
     165             :                                  const uint32_t timeout)
     166             : {
     167             :     Record::Result result;
     168           3 :     if (!_impl->waitRequest(requestID, result, timeout))
     169           1 :         return false;
     170             : 
     171           2 :     rPointer = result.rPointer;
     172           2 :     return true;
     173             : }
     174           1 : bool RequestHandler::waitRequest(const uint32_t requestID, uint32_t& rUint32,
     175             :                                  const uint32_t timeout)
     176             : {
     177             :     Record::Result result;
     178           1 :     if (!_impl->waitRequest(requestID, result, timeout))
     179           0 :         return false;
     180             : 
     181           1 :     rUint32 = result.rUint32;
     182           1 :     return true;
     183             : }
     184             : 
     185           1 : bool RequestHandler::waitRequest(const uint32_t requestID,
     186             :                                  servus::uint128_t& rUint128,
     187             :                                  const uint32_t timeout)
     188             : {
     189             :     Record::Result result;
     190           1 :     if (!_impl->waitRequest(requestID, result, timeout))
     191           0 :         return false;
     192             : 
     193           1 :     rUint128.high() = result.rUint128.high;
     194           1 :     rUint128.low() = result.rUint128.low;
     195           1 :     return true;
     196             : }
     197             : 
     198           1 : bool RequestHandler::waitRequest(const uint32_t requestID, bool& rBool,
     199             :                                  const uint32_t timeout)
     200             : {
     201             :     Record::Result result;
     202           1 :     if (!_impl->waitRequest(requestID, result, timeout))
     203           0 :         return false;
     204             : 
     205           1 :     rBool = result.rBool;
     206           1 :     return true;
     207             : }
     208             : 
     209           1 : bool RequestHandler::waitRequest(const uint32_t requestID)
     210             : {
     211             :     Record::Result result;
     212           1 :     return _impl->waitRequest(requestID, result, LB_TIMEOUT_INDEFINITE);
     213             : }
     214             : 
     215           6 : void* RequestHandler::getRequestData(const uint32_t requestID)
     216             : {
     217          12 :     ScopedFastWrite mutex(_impl->lock);
     218           6 :     RecordHashCIter i = _impl->requests.find(requestID);
     219           6 :     if (i == _impl->requests.end())
     220           0 :         return 0;
     221             : 
     222           6 :     return i->second->data;
     223             : }
     224             : 
     225           3 : void RequestHandler::serveRequest(const uint32_t requestID, void* result)
     226             : {
     227           3 :     Record* request = 0;
     228             :     {
     229           6 :         ScopedFastWrite mutex(_impl->lock);
     230           3 :         RecordHashCIter i = _impl->requests.find(requestID);
     231             : 
     232           3 :         if (i != _impl->requests.end())
     233           3 :             request = i->second;
     234             :     }
     235           3 :     if (request)
     236             :     {
     237           3 :         request->result.rPointer = result;
     238           3 :         request->lock.unlock();
     239             :     }
     240           3 : }
     241             : 
     242           1 : void RequestHandler::serveRequest(const uint32_t requestID, uint32_t result)
     243             : {
     244           1 :     Record* request = 0;
     245             :     {
     246           2 :         ScopedFastWrite mutex(_impl->lock);
     247           1 :         RecordHashCIter i = _impl->requests.find(requestID);
     248             : 
     249           1 :         if (i != _impl->requests.end())
     250           1 :             request = i->second;
     251             :     }
     252           1 :     if (request)
     253             :     {
     254           1 :         request->result.rUint32 = result;
     255           1 :         request->lock.unlock();
     256             :     }
     257           1 : }
     258             : 
     259           1 : void RequestHandler::serveRequest(const uint32_t requestID, bool result)
     260             : {
     261           1 :     Record* request = 0;
     262             :     {
     263           2 :         ScopedFastWrite mutex(_impl->lock);
     264           1 :         RecordHashCIter i = _impl->requests.find(requestID);
     265             : 
     266           1 :         if (i != _impl->requests.end())
     267           1 :             request = i->second;
     268             :     }
     269           1 :     if (request)
     270             :     {
     271           1 :         request->result.rBool = result;
     272           1 :         request->lock.unlock();
     273             :     }
     274           1 : }
     275             : 
     276           1 : void RequestHandler::serveRequest(const uint32_t requestID,
     277             :                                   const servus::uint128_t& result)
     278             : {
     279           1 :     Record* request = 0;
     280             :     {
     281           2 :         ScopedFastWrite mutex(_impl->lock);
     282           1 :         RecordHashCIter i = _impl->requests.find(requestID);
     283             : 
     284           1 :         if (i != _impl->requests.end())
     285           1 :             request = i->second;
     286             :     }
     287             : 
     288           1 :     if (request)
     289             :     {
     290           1 :         request->result.rUint128.low = result.low();
     291           1 :         request->result.rUint128.high = result.high();
     292           1 :         request->lock.unlock();
     293             :     }
     294           1 : }
     295             : 
     296           1 : bool RequestHandler::isRequestReady(const uint32_t requestID) const
     297             : {
     298           2 :     ScopedFastWrite mutex(_impl->lock);
     299           1 :     RecordHashCIter i = _impl->requests.find(requestID);
     300           1 :     if (i == _impl->requests.end())
     301           0 :         return false;
     302             : 
     303           1 :     Record* request = i->second;
     304           1 :     const bool isReady = request->lock.try_lock();
     305           1 :     if (isReady)
     306           1 :         request->lock.unlock();
     307           1 :     return isReady;
     308             : }
     309             : 
     310           2 : bool RequestHandler::hasPendingRequests() const
     311             : {
     312           2 :     return !_impl->requests.empty();
     313             : }
     314          75 : }

Generated by: LCOV version 1.11