diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-09-12 14:16:22 +0000 |
---|---|---|
committer | <> | 2014-10-24 11:04:40 +0000 |
commit | a77e3a63f004e6ee789fa05e4a5bbc333b1529f1 (patch) | |
tree | efe8a68996c19b7b0765ebc689937721d1d99cf7 /prober.py | |
download | sysv-ipc-tarball-master.tar.gz |
Imported from /home/lorry/working-area/delta_python-packages_sysv-ipc-tarball/sysv_ipc-0.6.8.tar.gz.HEADsysv_ipc-0.6.8master
Diffstat (limited to 'prober.py')
-rw-r--r-- | prober.py | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/prober.py b/prober.py new file mode 100644 index 0000000..08f5fe0 --- /dev/null +++ b/prober.py @@ -0,0 +1,186 @@ +import os.path +import os +import subprocess +import sys +import distutils.sysconfig + +# Set these to None for debugging or subprocess.PIPE to silence compiler +# warnings and errors. +STDOUT = subprocess.PIPE +STDERR = subprocess.PIPE +# STDOUT = None +# STDERR = None + +# This is the max length that I want a printed line to be. +MAX_LINE_LENGTH = 78 + +PYTHON_INCLUDE_DIR = os.path.dirname(distutils.sysconfig.get_config_h_filename()) +#print (PYTHON_INCLUDE_DIR) + +def line_wrap_paragraph(s): + # Format s with terminal-friendly line wraps. + done = False + beginning = 0 + end = MAX_LINE_LENGTH - 1 + lines = [ ] + while not done: + if end >= len(s): + done = True + lines.append(s[beginning:]) + else: + last_space = s[beginning:end].rfind(' ') + + lines.append(s[beginning:beginning + last_space]) + beginning += (last_space + 1) + end = beginning + MAX_LINE_LENGTH - 1 + + return lines + + +def print_bad_news(value_name, default): + s = "Setup can't determine %s on your system, so it will default to %s which may not be correct." \ + % (value_name, default) + plea = "Please report this message and your operating system info to the package maintainer listed in the README file." + + lines = line_wrap_paragraph(s) + [''] + line_wrap_paragraph(plea) + + border = '*' * MAX_LINE_LENGTH + + s = border + "\n* " + ('\n* '.join(lines)) + '\n' + border + + print (s) + + +def does_build_succeed(filename): + # Utility function that returns True if the file compiles and links + # successfully, False otherwise. + cmd = "cc -Wall -I%s -o ./prober/foo ./prober/%s" % \ + (PYTHON_INCLUDE_DIR, filename) + + p = subprocess.Popen(cmd, shell=True, stdout=STDOUT, stderr=STDERR) + + # p.wait() returns the process' return code, so 0 implies that + # the compile & link succeeded. + return not bool(p.wait()) + +def compile_and_run(filename, linker_options = ""): + # Utility function that returns the stdout output from running the + # compiled source file; None if the compile fails. + cmd = "cc -Wall -I%s -o ./prober/foo %s ./prober/%s" % \ + (PYTHON_INCLUDE_DIR, linker_options, filename) + + p = subprocess.Popen(cmd, shell=True, stdout=STDOUT, stderr=STDERR) + + if p.wait(): + # uh-oh, compile failed + return None + else: + s = subprocess.Popen(["./prober/foo"], + stdout=subprocess.PIPE).communicate()[0] + return s.strip().decode() + + +def sniff_semtimedop(): + return does_build_succeed("semtimedop_test.c") + + +def sniff_union_semun_defined(): + # AFAICT the semun union is supposed to be declared in one's code. + # However, a lot of legacy code gets this wrong and some header files + # define it, e.g.sys/sem.h on OS X where it's #ifdef-ed so that legacy + # code won't break. On some systems, it appears and disappears based + # on the #define value of _XOPEN_SOURCE. + return does_build_succeed("sniff_union_semun_defined.c") + + +def probe_semvmx(): + # This is the hardcoded default that I chose for two reasons. First, + # it's the default on my Mac so I know at least one system needs it + # this low. Second, it fits neatly into a 16-bit signed int which + # makes me hope that it's low enough to be safe on all systems. + semvmx = 32767 + + # FIXME -- Ways to get SEMVMX -- + # 1) Try to compile .c code assuming SEMVMX is #defined + # 2) Parse the output from `sysctl kern.sysv.semvmx` (doesn't work + # on OS X). + # 3) Parse the output from `ipcs -S` + # 4) Run .c code that loops, releasing a semaphore until semop() + # returns ERANGE or the value goes wonky. OS X lets the latter + # happen, which AFAICT is a violation of the spec. + + return semvmx + + + +def probe_page_size(): + DEFAULT_PAGE_SIZE = 4096 + + page_size = compile_and_run("probe_page_size.c") + + if page_size is None: + page_size = DEFAULT_PAGE_SIZE + print_bad_news("the value of PAGE_SIZE", page_size) + + return page_size + + +def probe(): + d = { "KEY_MAX" : "LONG_MAX", + "KEY_MIN" : "LONG_MIN" + } + + conditionals = [ "_SEM_SEMUN_UNDEFINED" ] + + f = open("VERSION") + version = f.read().strip() + f.close() + + d["SYSV_IPC_VERSION"] = '"%s"' % version + d["PAGE_SIZE"] = probe_page_size() + if sniff_semtimedop(): + d["SEMTIMEDOP_EXISTS"] = "" + d["SEMAPHORE_VALUE_MAX"] = probe_semvmx() + # Some (all?) Linux platforms #define _SEM_SEMUN_UNDEFINED if it's up + # to my code to declare this union, so I use that flag as my standard. + if not sniff_union_semun_defined(): + d["_SEM_SEMUN_UNDEFINED"] = "" + + + + msg = """/* +This header file was generated when you ran setup. Once created, the setup +process won't overwrite it, so you can adjust the values by hand and +recompile if you need to. + +To recreate this file, just delete it and re-run setup.py. + +KEY_MIN, KEY_MAX and SEMAPHORE_VALUE_MAX are stored internally in longs, so +you should never #define them to anything larger than LONG_MAX. +*/ + +""" + + filename = "probe_results.h" + if not os.path.exists(filename): + lines = [ ] + + for key in d: + if key in conditionals: + lines.append("#ifndef %s" % key) + + lines.append("#define %s\t\t%s" % (key, d[key])) + + if key in conditionals: + lines.append("#endif") + + # A trailing '\n' keeps compilers happy... + f = open(filename, "w") + f.write(msg + '\n'.join(lines) + '\n') + f.close() + + return d + +if __name__ == "__main__": + s = probe() + print (s) |