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 248861433 : inline void set()
38 : {
39 : while( true )
40 : {
41 143831737 : if( trySet( ))
42 77605764 : return;
43 100104097 : lunchbox::Thread::yield();
44 : }
45 : }
46 :
47 38802880 : inline void unset()
48 : {
49 38802880 : LBASSERT( _state == _writelocked );
50 38802880 : _state = _unlocked;
51 38791776 : }
52 :
53 134905387 : inline bool trySet()
54 : {
55 134905387 : if( !_state.compareAndSwap( _unlocked, _writelocked ))
56 104200542 : return false;
57 38802882 : LBASSERTINFO( isSetWrite(), _state );
58 38802882 : return true;
59 : }
60 :
61 41867040 : inline void setRead()
62 : {
63 : while( true )
64 : {
65 28431080 : if( trySetRead( ))
66 29779120 : return;
67 12944143 : lunchbox::Thread::yield();
68 : }
69 : }
70 :
71 24756414 : inline void unsetRead()
72 : {
73 : while( true )
74 : {
75 24756414 : LBASSERT( _state > _unlocked );
76 23822432 : memoryBarrier();
77 24559668 : const int32_t expected = _state;
78 23617294 : if( _state.compareAndSwap( expected, expected-1 ))
79 30384824 : return;
80 9810275 : }
81 : }
82 :
83 26783305 : inline bool trySetRead()
84 : {
85 26783305 : memoryBarrier();
86 28384953 : const int32_t state = _state;
87 : // Note: 0 used here since using _unlocked unexplicably gives
88 : // 'undefined reference to lunchbox::SpinLock::_unlocked'
89 27298191 : const int32_t expected = (state==_writelocked) ? 0 : state;
90 :
91 27298191 : if( !_state.compareAndSwap( expected, expected+1 ))
92 13280013 : return false;
93 :
94 15261894 : LBASSERTINFO( isSetRead(), _state << ", " << expected );
95 14984902 : return true;
96 : }
97 :
98 9015877 : inline bool isSet() { return ( _state != _unlocked ); }
99 50187239 : inline bool isSetWrite() { return ( _state == _writelocked ); }
100 28266311 : 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 38802407 : void SpinLock::set()
116 : {
117 38802407 : _impl->set();
118 38802882 : }
119 :
120 38802880 : void SpinLock::unset()
121 : {
122 38802880 : _impl->unset();
123 38802844 : }
124 :
125 0 : bool SpinLock::trySet()
126 : {
127 0 : return _impl->trySet();
128 : }
129 :
130 15149202 : void SpinLock::setRead()
131 : {
132 15149202 : _impl->setRead();
133 14889520 : }
134 :
135 14976373 : void SpinLock::unsetRead()
136 : {
137 14976373 : _impl->unsetRead();
138 15164446 : }
139 :
140 0 : bool SpinLock::trySetRead()
141 : {
142 0 : return _impl->trySetRead();
143 : }
144 :
145 9015877 : bool SpinLock::isSet()
146 : {
147 9015877 : return _impl->isSet();
148 : }
149 :
150 11384357 : bool SpinLock::isSetWrite()
151 : {
152 11384357 : return _impl->isSetWrite();
153 : }
154 :
155 14870885 : bool SpinLock::isSetRead()
156 : {
157 14870885 : return _impl->isSetRead();
158 : }
159 :
160 90 : }
|