LCOV - code coverage report
Current view: top level - lunchbox - spinLock.cpp (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 30 67 44.8 %
Date: 2018-10-03 05:33:11 Functions: 12 24 50.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2012-2017, Stefan Eilemann <eile@eyescale.ch>
       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 "spinLock.h"
      19             : #include <lunchbox/atomic.h>
      20             : #include <lunchbox/thread.h>
      21             : 
      22             : namespace lunchbox
      23             : {
      24             : namespace
      25             : {
      26             : static const long _writelocked = -1;
      27             : static const long _unlocked = 0;
      28             : }
      29             : 
      30             : class SpinLock::Impl
      31             : {
      32             : public:
      33          48 :     Impl()
      34          48 :         : _state(_unlocked)
      35             :     {
      36          48 :     }
      37             : 
      38          48 :     ~Impl() { _state = _unlocked; }
      39             : 
      40        8606 :     inline void set()
      41             :     {
      42             :         while (true)
      43             :         {
      44        9187 :             if (trySet())
      45       16120 :                 return;
      46         584 :             lunchbox::Thread::yield();
      47             :         }
      48             :     }
      49             : 
      50        8044 :     inline void unset()
      51             :     {
      52        8044 :         LBASSERT(_state == _writelocked);
      53        8068 :         _state = _unlocked;
      54        8067 :     }
      55             : 
      56        8605 :     inline bool trySet()
      57             :     {
      58        8605 :         if (!_state.compareAndSwap(_unlocked, _writelocked))
      59         584 :             return false;
      60        8056 :         LBASSERTINFO(isSetWrite(), _state);
      61        8060 :         return true;
      62             :     }
      63             : 
      64           0 :     inline void setRead()
      65             :     {
      66             :         while (true)
      67             :         {
      68           0 :             if (trySetRead())
      69           0 :                 return;
      70           0 :             lunchbox::Thread::yield();
      71             :         }
      72             :     }
      73             : 
      74           0 :     inline void unsetRead()
      75             :     {
      76             :         while (true)
      77             :         {
      78           0 :             LBASSERT(_state > _unlocked);
      79           0 :             memoryBarrier();
      80           0 :             const int32_t expected = _state;
      81           0 :             if (_state.compareAndSwap(expected, expected - 1))
      82           0 :                 return;
      83           0 :         }
      84             :     }
      85             : 
      86           0 :     inline bool trySetRead()
      87             :     {
      88           0 :         memoryBarrier();
      89           0 :         const int32_t state = _state;
      90             :         // Note: 0 used here since using _unlocked unexplicably gives
      91             :         //       'undefined reference to lunchbox::SpinLock::_unlocked'
      92           0 :         const int32_t expected = (state == _writelocked) ? 0 : state;
      93             : 
      94           0 :         if (!_state.compareAndSwap(expected, expected + 1))
      95           0 :             return false;
      96             : 
      97           0 :         LBASSERTINFO(isSetRead(), _state << ", " << expected);
      98           0 :         return true;
      99             :     }
     100             : 
     101           0 :     inline bool isSet() { return (_state != _unlocked); }
     102        8056 :     inline bool isSetWrite() { return (_state == _writelocked); }
     103           0 :     inline bool isSetRead() { return (_state > _unlocked); }
     104             : 
     105             : private:
     106             :     a_int32_t _state;
     107             : };
     108             : 
     109          48 : SpinLock::SpinLock()
     110          48 :     : _impl(new SpinLock::Impl)
     111             : {
     112          48 : }
     113             : 
     114          48 : SpinLock::~SpinLock()
     115             : {
     116          48 : }
     117             : 
     118        8048 : void SpinLock::set()
     119             : {
     120        8048 :     _impl->set();
     121        8060 : }
     122             : 
     123        8044 : void SpinLock::unset()
     124             : {
     125        8044 :     _impl->unset();
     126        8068 : }
     127             : 
     128           0 : bool SpinLock::trySet()
     129             : {
     130           0 :     return _impl->trySet();
     131             : }
     132             : 
     133           0 : void SpinLock::setRead()
     134             : {
     135           0 :     _impl->setRead();
     136           0 : }
     137             : 
     138           0 : void SpinLock::unsetRead()
     139             : {
     140           0 :     _impl->unsetRead();
     141           0 : }
     142             : 
     143           0 : bool SpinLock::trySetRead()
     144             : {
     145           0 :     return _impl->trySetRead();
     146             : }
     147             : 
     148           0 : bool SpinLock::isSet()
     149             : {
     150           0 :     return _impl->isSet();
     151             : }
     152             : 
     153           0 : bool SpinLock::isSetWrite()
     154             : {
     155           0 :     return _impl->isSetWrite();
     156             : }
     157             : 
     158           0 : bool SpinLock::isSetRead()
     159             : {
     160           0 :     return _impl->isSetRead();
     161             : }
     162          75 : }

Generated by: LCOV version 1.11