From 6915fe26da8dce41fc967d761f005390aa956161 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann <hansmi@google.com> Date: Thu, 13 Oct 2011 19:04:37 +0200 Subject: [PATCH] utils.cfunc: Cleanup, more flexibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Split code using ctypes directly into a helper class - Don't load βlibc.so.6β, but use handle for main program instead (see comment in code) - Clarify comment on errno with older ctypes versions - Rename unittest since it can't be used for other functions (modifies process environment at runtime) - Add boolean return value for βMlockallβ These changes are leftovers from some experiments with ctypes. Signed-off-by: Michael Hanselmann <hansmi@google.com> Reviewed-by: Iustin Pop <iustin@google.com> --- Makefile.am | 2 +- lib/utils/cfunc.py | 73 ++++++++++++------- ...> ganeti.utils.cfunc.mlockall_unittest.py} | 4 +- 3 files changed, 47 insertions(+), 32 deletions(-) rename test/{ganeti.utils.cfunc_unittest.py => ganeti.utils.cfunc.mlockall_unittest.py} (97%) diff --git a/Makefile.am b/Makefile.am index 2a513f15f..5031a5303 100644 --- a/Makefile.am +++ b/Makefile.am @@ -724,7 +724,7 @@ python_tests = \ test/ganeti.tools.ensure_dirs_unittest.py \ test/ganeti.uidpool_unittest.py \ test/ganeti.utils.algo_unittest.py \ - test/ganeti.utils.cfunc_unittest.py \ + test/ganeti.utils.cfunc.mlockall_unittest.py \ test/ganeti.utils.filelock_unittest.py \ test/ganeti.utils.hash_unittest.py \ test/ganeti.utils.io_unittest.py \ diff --git a/lib/utils/cfunc.py b/lib/utils/cfunc.py index ea14d6848..a1b3af49b 100644 --- a/lib/utils/cfunc.py +++ b/lib/utils/cfunc.py @@ -34,44 +34,61 @@ except ImportError: ctypes = None -# Flags for mlockall() (from bits/mman.h) +# Flags for mlockall(2) (from bits/mman.h) _MCL_CURRENT = 1 _MCL_FUTURE = 2 +class _FuncWrapper: + def __init__(self, ct): + """Initializes this class. + + """ + # Make use of a dlopen(3) feature whereby giving a NULL handle returns the + # main program. Functions from all previously loaded libraries can then be + # used. + mainprog = ct.CDLL(None) + + # The ctypes module before Python 2.6 does not have built-in functionality + # to access the global errno global (which, depending on the libc and build + # options, is per-thread), where function error codes are stored. Use GNU + # libc's way to retrieve errno(3) instead. + try: + errno_loc = getattr(mainprog, "__errno_location") + except AttributeError, err: + logging.debug("Unable to find errno location: %s", err) + errno_fn = None + else: + errno_loc.restype = ct.POINTER(ct.c_int) + errno_fn = lambda: errno_loc().contents.value + + self.errno_fn = errno_fn + + # Try to get mlockall(2) + self.mlockall_fn = getattr(mainprog, "mlockall", None) + + def Mlockall(_ctypes=ctypes): """Lock current process' virtual address space into RAM. - This is equivalent to the C call mlockall(MCL_CURRENT|MCL_FUTURE), - see mlock(2) for more details. This function requires ctypes module. + This is equivalent to the C call C{mlockall(MCL_CURRENT | MCL_FUTURE)}. See + mlockall(2) for more details. This function requires the C{ctypes} module. - @raises errors.NoCtypesError: if ctypes module is not found + @raises errors.NoCtypesError: If the C{ctypes} module is not found """ if _ctypes is None: raise errors.NoCtypesError() - try: - libc = _ctypes.cdll.LoadLibrary("libc.so.6") - except EnvironmentError, err: - logging.error("Failure trying to load libc: %s", err) - libc = None - if libc is None: - logging.error("Cannot set memory lock, ctypes cannot load libc") - return - - # Some older version of the ctypes module don't have built-in functionality - # to access the errno global variable, where function error codes are stored. - # By declaring this variable as a pointer to an integer we can then access - # its value correctly, should the mlockall call fail, in order to see what - # the actual error code was. - # pylint: disable=W0212 - libc.__errno_location.restype = _ctypes.POINTER(_ctypes.c_int) - - if libc.mlockall(_MCL_CURRENT | _MCL_FUTURE): - # pylint: disable=W0212 - logging.error("Cannot set memory lock: %s", - os.strerror(libc.__errno_location().contents.value)) - return - - logging.debug("Memory lock set") + funcs = _FuncWrapper(_ctypes) + + if funcs.mlockall_fn is None: + logging.debug("libc doesn't support mlockall(2)") + else: + if funcs.mlockall_fn(_MCL_CURRENT | _MCL_FUTURE) == 0: + logging.debug("Memory lock set") + return True + + logging.error("Cannot set memory lock: %s", os.strerror(funcs.errno_fn())) + + return False diff --git a/test/ganeti.utils.cfunc_unittest.py b/test/ganeti.utils.cfunc.mlockall_unittest.py similarity index 97% rename from test/ganeti.utils.cfunc_unittest.py rename to test/ganeti.utils.cfunc.mlockall_unittest.py index 8c5c7469b..bafa71c8d 100755 --- a/test/ganeti.utils.cfunc_unittest.py +++ b/test/ganeti.utils.cfunc.mlockall_unittest.py @@ -41,17 +41,15 @@ class TestMlockallWithCtypes(unittest.TestCase): """Whether Mlockall() works if ctypes is present. """ - def test(self): if utils.ctypes: - utils.Mlockall() + self.assertTrue(utils.Mlockall()) class TestMlockallWithNoCtypes(unittest.TestCase): """Whether Mlockall() raises an error if ctypes is not present. """ - def test(self): self.assertRaises(errors.NoCtypesError, utils.Mlockall, _ctypes=None) -- GitLab