ia64/xen-unstable

changeset 18771:484cf12ba667

xend: Add a multi-reader-single-writer lock implementation

This patch adds a reader-writer lock primitive to xend since python
does not provide it by default. The implementation is based on a
condition variable. Some test code is appended at the end of the file.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Nov 05 10:22:19 2008 +0000 (2008-11-05)
parents 4bfc67b09e9c
children ef202be3cf54
files tools/python/xen/util/rwlock.py
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/python/xen/util/rwlock.py	Wed Nov 05 10:22:19 2008 +0000
     1.3 @@ -0,0 +1,137 @@
     1.4 +""" Reader-writer lock implementation based on a condition variable """
     1.5 +
     1.6 +#============================================================================
     1.7 +# This library is free software; you can redistribute it and/or
     1.8 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
     1.9 +# License as published by the Free Software Foundation.
    1.10 +#
    1.11 +# This library is distributed in the hope that it will be useful,
    1.12 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.13 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.14 +# Lesser General Public License for more details.
    1.15 +#
    1.16 +# You should have received a copy of the GNU Lesser General Public
    1.17 +# License along with this library; if not, write to the Free Software
    1.18 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.19 +#============================================================================
    1.20 +# Copyright (C) 2008 International Business Machines Corp.
    1.21 +# Author: Stefan Berger <stefanb@us.ibm.com>
    1.22 +#============================================================================
    1.23 +
    1.24 +from threading import Condition
    1.25 +
    1.26 +class RWLock:
    1.27 +
    1.28 +    RWLOCK_STATE_WRITER = -1
    1.29 +    RWLOCK_STATE_UNUSED = 0
    1.30 +
    1.31 +    def __init__(self):
    1.32 +        self.__condition = Condition()
    1.33 +        self.__state = RWLock.RWLOCK_STATE_UNUSED
    1.34 +        self.__blocked_writers = 0
    1.35 +
    1.36 +    def acquire_reader(self):
    1.37 +        self.__condition.acquire()
    1.38 +        while True:
    1.39 +            if self.__state == RWLock.RWLOCK_STATE_WRITER:
    1.40 +                self.__condition.wait()
    1.41 +            else:
    1.42 +                break
    1.43 +        self.__state += 1
    1.44 +        self.__condition.release()
    1.45 +
    1.46 +    def acquire_writer(self):
    1.47 +        self.__condition.acquire()
    1.48 +        self.__acquire_writer(RWLock.RWLOCK_STATE_UNUSED)
    1.49 +        self.__condition.release()
    1.50 +
    1.51 +    def __acquire_writer(self, wait_for_state):
    1.52 +        while True:
    1.53 +            if self.__state == wait_for_state:
    1.54 +                self.__state = RWLock.RWLOCK_STATE_WRITER
    1.55 +                break
    1.56 +            else:
    1.57 +                self.__blocked_writers += 1
    1.58 +                self.__condition.wait()
    1.59 +                self.__blocked_writers -= 1
    1.60 +
    1.61 +    def release(self):
    1.62 +        self.__condition.acquire()
    1.63 +        if self.__state == RWLock.RWLOCK_STATE_WRITER:
    1.64 +            self.__state = RWLock.RWLOCK_STATE_UNUSED
    1.65 +        elif self.__state == RWLock.RWLOCK_STATE_UNUSED:
    1.66 +            assert False, 'Lock not in use.'
    1.67 +        else:
    1.68 +            self.__state -= 1
    1.69 +        self.__condition.notifyAll()
    1.70 +        self.__condition.release()
    1.71 +
    1.72 +
    1.73 +if __name__ == '__main__':
    1.74 +    from threading import Thread
    1.75 +    from time import sleep
    1.76 +
    1.77 +    rwlock = RWLock()
    1.78 +
    1.79 +    class Base(Thread):
    1.80 +        def __init__(self, name, timeout):
    1.81 +            self.name = name
    1.82 +            self.timeout = timeout
    1.83 +            Thread.__init__(self)
    1.84 +
    1.85 +    class Reader(Base):
    1.86 +        def __init__(self, name = 'Reader', timeout = 10):
    1.87 +            Base.__init__(self, name, timeout)
    1.88 +
    1.89 +        def run(self):
    1.90 +            print '%s begin' % self.name
    1.91 +            rwlock.acquire_reader()
    1.92 +            print '%s acquired' % self.name
    1.93 +            sleep(self.timeout)
    1.94 +            rwlock.release()
    1.95 +            print '%s end' % self.name
    1.96 +
    1.97 +    class ReaderTwice(Base):
    1.98 +        def __init__(self, name = 'Reader', timeout = 10):
    1.99 +            Base.__init__(self, name, timeout)
   1.100 +
   1.101 +        def run(self):
   1.102 +            print '%s begin' % self.name
   1.103 +            rwlock.acquire_reader()
   1.104 +            print '%s acquired once' % self.name
   1.105 +            sleep(self.timeout)
   1.106 +            rwlock.acquire_reader()
   1.107 +            print '%s acquired twice' % self.name
   1.108 +            sleep(self.timeout)
   1.109 +            rwlock.release()
   1.110 +            rwlock.release()
   1.111 +            print '%s end' % self.name
   1.112 +
   1.113 +    class Writer(Base):
   1.114 +        def __init__(self, name = 'Writer', timeout = 10):
   1.115 +            Base.__init__(self, name, timeout)
   1.116 +
   1.117 +        def run(self):
   1.118 +            print '%s begin' % self.name
   1.119 +            rwlock.acquire_writer()
   1.120 +            print '%s acquired' % self.name
   1.121 +            sleep(self.timeout)
   1.122 +            rwlock.release()
   1.123 +            print '%s end' % self.name
   1.124 +
   1.125 +    def run_test(threadlist, msg):
   1.126 +        print msg
   1.127 +        for t in threadlist:
   1.128 +            t.start()
   1.129 +            sleep(1)
   1.130 +        for t in threads:
   1.131 +            t.join()
   1.132 +        print 'Done\n\n'
   1.133 +
   1.134 +    threads = []
   1.135 +    threads.append( Reader('R1', 4) )
   1.136 +    threads.append( Reader('R2', 4) )
   1.137 +    threads.append( Writer('W1', 4) )
   1.138 +    threads.append( Reader('R3', 4) )
   1.139 +    run_test(threads,
   1.140 +             'Test: readers may bypass blocked writers')