From 20b93811aebdb5947dddf84a5117e51971353278 Mon Sep 17 00:00:00 2001 From: David Lehman Date: Thu, 7 Aug 2014 17:34:03 -0500 Subject: [PATCH 06/26] Add some utilities related to multithreading. --- blivet/threads.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 blivet/threads.py diff --git a/blivet/threads.py b/blivet/threads.py new file mode 100644 index 0000000..2073431 --- /dev/null +++ b/blivet/threads.py @@ -0,0 +1,70 @@ +# threads.py +# Utilities related to multithreading. +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# the GNU General Public License v.2, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY expressed or implied, including the implied warranties of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the +# GNU General Public License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the +# source code or documentation are not subject to the GNU General Public +# License and may only be used or replicated with the express permission of +# Red Hat, Inc. +# +# Red Hat Author(s): David Lehman +# + +from threading import _RLock, currentThread +from functools import wraps +from types import FunctionType + +from .util import ObjectID + +import logging +log = logging.getLogger("blivet") + +class RLockID(_RLock): + """ An RLock with a user-specified integer id. """ + def __init__(self, *args, **kwargs): + self.id = args[0] + super(RLockID, self).__init__(*args, **kwargs) + + def __repr__(self): + s = super(RLockID, self).__repr__() + return "%s id=%s>" % (s[:-1], self.id) + + def __enter__(self, *args, **kwargs): + super(RLockID, self).acquire(*args, **kwargs) + log.debug("acquired %s", self) + + def __exit__(self, *args, **kwargs): + super(RLockID, self).release() + log.debug("released %s", self) + +class LockedObjectID(ObjectID): + """ Base class with unique instance id and reentrant lock. """ + def __new__(cls, *args, **kwargs): + self = super(LockedObjectID, cls).__new__(cls, *args, **kwargs) + self.lock = RLockID(self.id) # pylint: disable=attribute-defined-outside-init + return self + +def exclusive(m): + """ Run a bound method after aqcuiring the instance's lock. """ + @wraps(m) + def run_with_lock(*args, **kwargs): + # When the decorator is applied during creation of the method's class + # instance we have a function object -- not a method. As a result, we + # cannot use m.__self__ and instead must rely on the fact that the + # instance is always passed as the first argument to the method. + log.debug("thread %s acquiring lock %s before calling %s", + currentThread().name, args[0].lock, m.func_code.co_name) + with args[0].lock: + return m(*args, **kwargs) + + return run_with_lock -- 1.9.3