LCOV - code coverage report
Current view: top level - lunchbox - requestHandler.cpp (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 129 136 94.9 %
Date: 2017-08-03 05:21:41 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             :         const bool requestServed =
     100           7 :             request->lock.try_lock_for(std::chrono::milliseconds(timeout));
     101           7 :         if (requestServed)
     102             :         {
     103           6 :             result = request->result;
     104           6 :             unregisterRequest(requestID_);
     105             :         }
     106             : 
     107           7 :         return requestServed;
     108             :     }
     109             : 
     110           7 :     void unregisterRequest(const uint32_t requestID_)
     111             :     {
     112          14 :         ScopedFastWrite mutex(lock);
     113           7 :         RecordHash::iterator i = requests.find(requestID_);
     114           7 :         if (i == requests.end())
     115           0 :             return;
     116             : 
     117           7 :         Record* request = i->second;
     118           7 :         requests.erase(i);
     119           7 :         freeRecords.push_front(request);
     120             :     }
     121             : 
     122             :     mutable lunchbox::SpinLock lock;
     123             :     uint32_t requestID;
     124             :     RecordHash requests;
     125             :     std::list<Record*> freeRecords;
     126             : };
     127             : }
     128             : // @endcond
     129             : 
     130           1 : RequestHandler::RequestHandler()
     131           1 :     : _impl(new detail::RequestHandler)
     132             : {
     133           1 : }
     134             : 
     135           5 : RequestHandler::~RequestHandler()
     136             : {
     137           7 :     while (!_impl->freeRecords.empty())
     138             :     {
     139           3 :         Record* request = _impl->freeRecords.front();
     140           3 :         _impl->freeRecords.pop_front();
     141           3 :         delete request;
     142             :     }
     143           1 :     delete _impl;
     144           1 : }
     145             : 
     146           7 : uint32_t RequestHandler::_register(void* data)
     147             : {
     148           7 :     return _impl->registerRequest(data);
     149             : }
     150             : 
     151           1 : void RequestHandler::unregisterRequest(const uint32_t requestID)
     152             : {
     153           1 :     _impl->unregisterRequest(requestID);
     154           1 : }
     155             : 
     156           3 : bool RequestHandler::waitRequest(const uint32_t requestID, void*& rPointer,
     157             :                                  const uint32_t timeout)
     158             : {
     159             :     Record::Result result;
     160           3 :     if (!_impl->waitRequest(requestID, result, timeout))
     161           1 :         return false;
     162             : 
     163           2 :     rPointer = result.rPointer;
     164           2 :     return true;
     165             : }
     166           1 : bool RequestHandler::waitRequest(const uint32_t requestID, uint32_t& rUint32,
     167             :                                  const uint32_t timeout)
     168             : {
     169             :     Record::Result result;
     170           1 :     if (!_impl->waitRequest(requestID, result, timeout))
     171           0 :         return false;
     172             : 
     173           1 :     rUint32 = result.rUint32;
     174           1 :     return true;
     175             : }
     176             : 
     177           1 : bool RequestHandler::waitRequest(const uint32_t requestID,
     178             :                                  servus::uint128_t& rUint128,
     179             :                                  const uint32_t timeout)
     180             : {
     181             :     Record::Result result;
     182           1 :     if (!_impl->waitRequest(requestID, result, timeout))
     183           0 :         return false;
     184             : 
     185           1 :     rUint128.high() = result.rUint128.high;
     186           1 :     rUint128.low() = result.rUint128.low;
     187           1 :     return true;
     188             : }
     189             : 
     190           1 : bool RequestHandler::waitRequest(const uint32_t requestID, bool& rBool,
     191             :                                  const uint32_t timeout)
     192             : {
     193             :     Record::Result result;
     194           1 :     if (!_impl->waitRequest(requestID, result, timeout))
     195           0 :         return false;
     196             : 
     197           1 :     rBool = result.rBool;
     198           1 :     return true;
     199             : }
     200           1 : bool RequestHandler::waitRequest(const uint32_t requestID)
     201             : {
     202             :     Record::Result result;
     203           1 :     return _impl->waitRequest(requestID, result, LB_TIMEOUT_INDEFINITE);
     204             : }
     205             : 
     206           6 : void* RequestHandler::getRequestData(const uint32_t requestID)
     207             : {
     208          12 :     ScopedFastWrite mutex(_impl->lock);
     209           6 :     RecordHashCIter i = _impl->requests.find(requestID);
     210           6 :     if (i == _impl->requests.end())
     211           0 :         return 0;
     212             : 
     213           6 :     return i->second->data;
     214             : }
     215             : 
     216           3 : void RequestHandler::serveRequest(const uint32_t requestID, void* result)
     217             : {
     218           3 :     Record* request = 0;
     219             :     {
     220           6 :         ScopedFastWrite mutex(_impl->lock);
     221           3 :         RecordHashCIter i = _impl->requests.find(requestID);
     222             : 
     223           3 :         if (i != _impl->requests.end())
     224           3 :             request = i->second;
     225             :     }
     226           3 :     if (request)
     227             :     {
     228           3 :         request->result.rPointer = result;
     229           3 :         request->lock.unlock();
     230             :     }
     231           3 : }
     232             : 
     233           1 : void RequestHandler::serveRequest(const uint32_t requestID, uint32_t result)
     234             : {
     235           1 :     Record* request = 0;
     236             :     {
     237           2 :         ScopedFastWrite mutex(_impl->lock);
     238           1 :         RecordHashCIter i = _impl->requests.find(requestID);
     239             : 
     240           1 :         if (i != _impl->requests.end())
     241           1 :             request = i->second;
     242             :     }
     243           1 :     if (request)
     244             :     {
     245           1 :         request->result.rUint32 = result;
     246           1 :         request->lock.unlock();
     247             :     }
     248           1 : }
     249             : 
     250           1 : void RequestHandler::serveRequest(const uint32_t requestID, bool result)
     251             : {
     252           1 :     Record* request = 0;
     253             :     {
     254           2 :         ScopedFastWrite mutex(_impl->lock);
     255           1 :         RecordHashCIter i = _impl->requests.find(requestID);
     256             : 
     257           1 :         if (i != _impl->requests.end())
     258           1 :             request = i->second;
     259             :     }
     260           1 :     if (request)
     261             :     {
     262           1 :         request->result.rBool = result;
     263           1 :         request->lock.unlock();
     264             :     }
     265           1 : }
     266             : 
     267           1 : void RequestHandler::serveRequest(const uint32_t requestID,
     268             :                                   const servus::uint128_t& result)
     269             : {
     270           1 :     Record* request = 0;
     271             :     {
     272           2 :         ScopedFastWrite mutex(_impl->lock);
     273           1 :         RecordHashCIter i = _impl->requests.find(requestID);
     274             : 
     275           1 :         if (i != _impl->requests.end())
     276           1 :             request = i->second;
     277             :     }
     278             : 
     279           1 :     if (request)
     280             :     {
     281           1 :         request->result.rUint128.low = result.low();
     282           1 :         request->result.rUint128.high = result.high();
     283           1 :         request->lock.unlock();
     284             :     }
     285           1 : }
     286             : 
     287           1 : bool RequestHandler::isRequestReady(const uint32_t requestID) const
     288             : {
     289           2 :     ScopedFastWrite mutex(_impl->lock);
     290           1 :     RecordHashCIter i = _impl->requests.find(requestID);
     291           1 :     if (i == _impl->requests.end())
     292           0 :         return false;
     293             : 
     294           1 :     Record* request = i->second;
     295           1 :     const bool isReady = request->lock.try_lock();
     296           1 :     if (isReady)
     297           1 :         request->lock.unlock();
     298           1 :     return isReady;
     299             : }
     300             : 
     301           2 : bool RequestHandler::hasPendingRequests() const
     302             : {
     303           2 :     return !_impl->requests.empty();
     304             : }
     305          75 : }

Generated by: LCOV version 1.11