Line data Source code
1 :
2 : /* Copyright (c) 2012, 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 : namespace detail
30 : {
31 : class SpinLock
32 : {
33 : public:
34 428 : SpinLock() : _state( _unlocked ) {}
35 428 : ~SpinLock() { _state = _unlocked; }
36 :
37 94406690 : inline void set()
38 : {
39 : while( true )
40 : {
41 69797871 : if( trySet( ))
42 90384974 : return;
43 24343239 : lunchbox::Thread::yield();
44 : }
45 : }
46 :
47 45192485 : inline void unset()
48 : {
49 45192485 : LBASSERT( _state == _writelocked );
50 45192485 : _state = _unlocked;
51 45192381 : }
52 :
53 68615003 : inline bool trySet()
54 : {
55 68615003 : if( !_state.compareAndSwap( _unlocked, _writelocked ))
56 24519062 : return false;
57 45192487 : LBASSERTINFO( isSetWrite(), _state );
58 45192487 : return true;
59 : }
60 :
61 32973355 : inline void setRead()
62 : {
63 : while( true )
64 : {
65 27264066 : if( trySetRead( ))
66 42965524 : return;
67 5619484 : lunchbox::Thread::yield();
68 : }
69 : }
70 :
71 24311806 : inline void unsetRead()
72 : {
73 : while( true )
74 : {
75 24311806 : LBASSERT( _state > _unlocked );
76 24081169 : memoryBarrier();
77 24327255 : const int32_t expected = _state;
78 24153113 : if( _state.compareAndSwap( expected, expected-1 ))
79 43295658 : return;
80 2820713 : }
81 : }
82 :
83 26998602 : inline bool trySetRead()
84 : {
85 26998602 : memoryBarrier();
86 27347069 : const int32_t state = _state;
87 : // Note: 0 used here since using _unlocked unexplicably gives
88 : // 'undefined reference to lunchbox::SpinLock::_unlocked'
89 27062950 : const int32_t expected = (state==_writelocked) ? 0 : state;
90 :
91 27062950 : if( !_state.compareAndSwap( expected, expected+1 ))
92 5658173 : return false;
93 :
94 21663849 : LBASSERTINFO( isSetRead(), _state << ", " << expected );
95 21529973 : return true;
96 : }
97 :
98 11718502 : inline bool isSet() { return ( _state != _unlocked ); }
99 60263826 : inline bool isSetWrite() { return ( _state == _writelocked ); }
100 42540995 : inline bool isSetRead() { return ( _state > _unlocked ); }
101 :
102 : private:
103 : a_int32_t _state;
104 : };
105 : }
106 :
107 428 : SpinLock::SpinLock()
108 428 : : _impl( new detail::SpinLock ) {}
109 :
110 428 : SpinLock::~SpinLock()
111 : {
112 428 : delete _impl;
113 428 : }
114 :
115 45192467 : void SpinLock::set()
116 : {
117 45192467 : _impl->set();
118 45192487 : }
119 :
120 45192485 : void SpinLock::unset()
121 : {
122 45192485 : _impl->unset();
123 45192482 : }
124 :
125 0 : bool SpinLock::trySet()
126 : {
127 0 : return _impl->trySet();
128 : }
129 :
130 21593854 : void SpinLock::setRead()
131 : {
132 21593854 : _impl->setRead();
133 21497816 : }
134 :
135 21508290 : void SpinLock::unsetRead()
136 : {
137 21508290 : _impl->unsetRead();
138 21635162 : }
139 :
140 0 : bool SpinLock::trySetRead()
141 : {
142 0 : return _impl->trySetRead();
143 : }
144 :
145 11718502 : bool SpinLock::isSet()
146 : {
147 11718502 : return _impl->isSet();
148 : }
149 :
150 15071339 : bool SpinLock::isSetWrite()
151 : {
152 15071339 : return _impl->isSetWrite();
153 : }
154 :
155 21482797 : bool SpinLock::isSetRead()
156 : {
157 21482797 : return _impl->isSetRead();
158 : }
159 :
160 87 : }
|