Initial commit
[ta/config-manager.git] / cmframework / src / cmframework / server / cmeventletrwlock.py
1 # Copyright 2019 Nokia
2
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 from __future__ import print_function
15 from eventlet import greenthread, hubs
16
17
18 class CMEventletRWLock(object):
19     def __init__(self):
20         self.counter = 0
21         self._read_waiters = set()
22         self._write_waiters = set()
23
24     def reader(self):
25         return self.Reader(self)
26
27     def writer(self):
28         return self.Writer(self)
29
30     class Base(object):
31         def __init__(self, parent):
32             self.parent = parent
33
34         def _acquire(self, waiters):
35             waiters.add(greenthread.getcurrent())
36
37             try:
38                 while self.parent.counter != 0:
39                     hubs.get_hub().switch()
40             finally:
41                 waiters.discard(greenthread.getcurrent())
42
43         def _exit(self):
44             for waiters, fn in (
45                     (self.parent._read_waiters, lambda x: x >= 0),
46                     (self.parent._write_waiters, lambda x: x == 0),
47             ):
48                 if not waiters:
49                     continue
50
51                 hubs.get_hub().schedule_call_global(
52                     0, self._release, waiters, fn,
53                 )
54
55         def _release(self, waiters, fn):
56             if waiters and fn(self.parent.counter):
57                 waiters.pop().switch()
58
59     class Reader(Base):
60         def __enter__(self):
61             if self.parent.counter < 0:
62                 self._acquire(self.parent._read_waiters)
63             self.parent.counter += 1
64
65         def __exit__(self, *args, **kwargs):
66             self.parent.counter -= 1
67             self._exit()
68
69     class Writer(Base):
70         def __enter__(self):
71             if self.parent.counter != 0:
72                 self._acquire(self.parent._write_waiters)
73             self.parent.counter -= 1
74
75         def __exit__(self, *args, **kwargs):
76             self.parent.counter += 1
77             self._exit()
78
79
80 def main():
81     lock = CMEventletRWLock()
82     with lock.reader():
83         print('Got reader lock')
84
85     with lock.writer():
86         print('Got write lock')
87
88
89 if __name__ == '__main__':
90     main()