diff options
author | Kevin Cheng <kevcheng@google.com> | 2019-04-18 11:31:16 -0700 |
---|---|---|
committer | Kevin Cheng <kevcheng@google.com> | 2019-05-02 13:59:40 -0700 |
commit | 757c264bc10ebc71074ee3f5fb66d670667a09bc (patch) | |
tree | 26c7f7b74c752db99d9b0ac1f94fc592aca1e53a /testing/embedding | |
parent | 99013222844839c42437f16eace25f4e6a8a8b20 (diff) | |
download | cffi-757c264bc10ebc71074ee3f5fb66d670667a09bc.tar.gz |
Add in cffi 1.12.2 (e0c7666)
Since this is a mercurial repo, d/led zip of src:
https://bitbucket.org/cffi/cffi/get/v1.12.2.zip
Also add in misc METADATA/NOTICE/Android.bp/etc files.
Bug: 122778810
Test: None
Change-Id: I36c58ed07a2cdd4d9d11831908175a5c988f33c1
Diffstat (limited to 'testing/embedding')
-rw-r--r-- | testing/embedding/__init__.py | 0 | ||||
-rw-r--r-- | testing/embedding/add1-test.c | 21 | ||||
-rw-r--r-- | testing/embedding/add1.py | 33 | ||||
-rw-r--r-- | testing/embedding/add2-test.c | 14 | ||||
-rw-r--r-- | testing/embedding/add2.py | 29 | ||||
-rw-r--r-- | testing/embedding/add3.py | 24 | ||||
-rw-r--r-- | testing/embedding/add_recursive-test.c | 27 | ||||
-rw-r--r-- | testing/embedding/add_recursive.py | 33 | ||||
-rw-r--r-- | testing/embedding/empty.py | 10 | ||||
-rw-r--r-- | testing/embedding/initerror.py | 18 | ||||
-rw-r--r-- | testing/embedding/perf-test.c | 90 | ||||
-rw-r--r-- | testing/embedding/perf.py | 21 | ||||
-rw-r--r-- | testing/embedding/test_basic.py | 207 | ||||
-rw-r--r-- | testing/embedding/test_performance.py | 52 | ||||
-rw-r--r-- | testing/embedding/test_recursive.py | 15 | ||||
-rw-r--r-- | testing/embedding/test_thread.py | 61 | ||||
-rw-r--r-- | testing/embedding/test_tlocal.py | 10 | ||||
-rw-r--r-- | testing/embedding/thread-test.h | 96 | ||||
-rw-r--r-- | testing/embedding/thread1-test.c | 43 | ||||
-rw-r--r-- | testing/embedding/thread2-test.c | 57 | ||||
-rw-r--r-- | testing/embedding/thread3-test.c | 56 | ||||
-rw-r--r-- | testing/embedding/tlocal-test.c | 47 | ||||
-rw-r--r-- | testing/embedding/tlocal.py | 33 |
23 files changed, 997 insertions, 0 deletions
diff --git a/testing/embedding/__init__.py b/testing/embedding/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/testing/embedding/__init__.py diff --git a/testing/embedding/add1-test.c b/testing/embedding/add1-test.c new file mode 100644 index 0000000..b9ede18 --- /dev/null +++ b/testing/embedding/add1-test.c @@ -0,0 +1,21 @@ +#include <stdio.h> + +#ifdef _MSC_VER +#include <windows.h> +#endif + +extern int add1(int, int); + + +int main(void) +{ + int x, y; + x = add1(40, 2); + y = add1(100, -5); + printf("got: %d %d\n", x, y); +#ifdef _MSC_VER + if (x == 0 && y == 0) + Sleep(2000); +#endif + return 0; +} diff --git a/testing/embedding/add1.py b/testing/embedding/add1.py new file mode 100644 index 0000000..e5b3de1 --- /dev/null +++ b/testing/embedding/add1.py @@ -0,0 +1,33 @@ +import cffi + +ffi = cffi.FFI() + +ffi.embedding_api(""" + int add1(int, int); +""") + +ffi.embedding_init_code(r""" + import sys, time + sys.stdout.write("preparing") + for i in range(3): + sys.stdout.flush() + time.sleep(0.2) + sys.stdout.write(".") + sys.stdout.write("\n") + + from _add1_cffi import ffi + + int(ord("A")) # check that built-ins are there + + @ffi.def_extern() + def add1(x, y): + sys.stdout.write("adding %d and %d\n" % (x, y)) + sys.stdout.flush() + return x + y +""") + +ffi.set_source("_add1_cffi", """ +""") + +fn = ffi.compile(verbose=True) +print('FILENAME: %s' % (fn,)) diff --git a/testing/embedding/add2-test.c b/testing/embedding/add2-test.c new file mode 100644 index 0000000..9620843 --- /dev/null +++ b/testing/embedding/add2-test.c @@ -0,0 +1,14 @@ +#include <stdio.h> + +extern int add1(int, int); +extern int add2(int, int, int); + + +int main(void) +{ + int x, y; + x = add1(40, 2); + y = add2(100, -5, -20); + printf("got: %d %d\n", x, y); + return 0; +} diff --git a/testing/embedding/add2.py b/testing/embedding/add2.py new file mode 100644 index 0000000..311a464 --- /dev/null +++ b/testing/embedding/add2.py @@ -0,0 +1,29 @@ +import cffi + +ffi = cffi.FFI() + +ffi.embedding_api(""" + int add2(int, int, int); +""") + +ffi.embedding_init_code(r""" + import sys + sys.stdout.write("prepADD2\n") + + assert '_add2_cffi' in sys.modules + m = sys.modules['_add2_cffi'] + import _add2_cffi + ffi = _add2_cffi.ffi + + @ffi.def_extern() + def add2(x, y, z): + sys.stdout.write("adding %d and %d and %d\n" % (x, y, z)) + sys.stdout.flush() + return x + y + z +""") + +ffi.set_source("_add2_cffi", """ +""") + +fn = ffi.compile(verbose=True) +print('FILENAME: %s' % (fn,)) diff --git a/testing/embedding/add3.py b/testing/embedding/add3.py new file mode 100644 index 0000000..1361912 --- /dev/null +++ b/testing/embedding/add3.py @@ -0,0 +1,24 @@ +import cffi + +ffi = cffi.FFI() + +ffi.embedding_api(""" + int add3(int, int, int, int); +""") + +ffi.embedding_init_code(r""" + from _add3_cffi import ffi + import sys + + @ffi.def_extern() + def add3(x, y, z, t): + sys.stdout.write("adding %d, %d, %d, %d\n" % (x, y, z, t)) + sys.stdout.flush() + return x + y + z + t +""") + +ffi.set_source("_add3_cffi", """ +""") + +fn = ffi.compile(verbose=True) +print('FILENAME: %s' % (fn,)) diff --git a/testing/embedding/add_recursive-test.c b/testing/embedding/add_recursive-test.c new file mode 100644 index 0000000..cd29b79 --- /dev/null +++ b/testing/embedding/add_recursive-test.c @@ -0,0 +1,27 @@ +#include <stdio.h> + +#ifdef _MSC_VER +# define DLLIMPORT __declspec(dllimport) +#else +# define DLLIMPORT extern +#endif + +DLLIMPORT int add_rec(int, int); +DLLIMPORT int (*my_callback)(int); + +static int some_callback(int x) +{ + printf("some_callback(%d)\n", x); + fflush(stdout); + return add_rec(x, 9); +} + +int main(void) +{ + int x, y; + my_callback = some_callback; + x = add_rec(40, 2); + y = add_rec(100, -5); + printf("got: %d %d\n", x, y); + return 0; +} diff --git a/testing/embedding/add_recursive.py b/testing/embedding/add_recursive.py new file mode 100644 index 0000000..9fa463d --- /dev/null +++ b/testing/embedding/add_recursive.py @@ -0,0 +1,33 @@ +import cffi + +ffi = cffi.FFI() + +ffi.embedding_api(""" + int (*my_callback)(int); + int add_rec(int, int); +""") + +ffi.embedding_init_code(r""" + from _add_recursive_cffi import ffi, lib + import sys + print("preparing REC") + sys.stdout.flush() + + @ffi.def_extern() + def add_rec(x, y): + print("adding %d and %d" % (x, y)) + sys.stdout.flush() + return x + y + + x = lib.my_callback(400) + print('<<< %d >>>' % (x,)) +""") + +ffi.set_source("_add_recursive_cffi", """ +/* use CFFI_DLLEXPORT: on windows, it expands to __declspec(dllexport), + which is needed to export a variable from a dll */ +CFFI_DLLEXPORT int (*my_callback)(int); +""") + +fn = ffi.compile(verbose=True) +print('FILENAME: %s' % (fn,)) diff --git a/testing/embedding/empty.py b/testing/embedding/empty.py new file mode 100644 index 0000000..aa8d830 --- /dev/null +++ b/testing/embedding/empty.py @@ -0,0 +1,10 @@ +import cffi + +ffi = cffi.FFI() + +ffi.embedding_api("") + +ffi.set_source("_empty_cffi", "") + +fn = ffi.compile(verbose=True) +print('FILENAME: %s' % (fn,)) diff --git a/testing/embedding/initerror.py b/testing/embedding/initerror.py new file mode 100644 index 0000000..775cf56 --- /dev/null +++ b/testing/embedding/initerror.py @@ -0,0 +1,18 @@ +import cffi + +ffi = cffi.FFI() + +ffi.embedding_api(""" + int add1(int, int); +""") + +ffi.embedding_init_code(r""" + raise KeyError +""") + +ffi.set_source("_initerror_cffi", """ +""") + +fn = ffi.compile(verbose=True) +print('FILENAME: %s' % (fn,)) + diff --git a/testing/embedding/perf-test.c b/testing/embedding/perf-test.c new file mode 100644 index 0000000..2195bf5 --- /dev/null +++ b/testing/embedding/perf-test.c @@ -0,0 +1,90 @@ +#include <stdio.h> +#include <assert.h> +#include <sys/time.h> +#ifdef PTEST_USE_THREAD +# include <pthread.h> +static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; +static int remaining; +#endif + + +extern int add1(int, int); + + +static double time_delta(struct timeval *stop, struct timeval *start) +{ + return (stop->tv_sec - start->tv_sec) + + 1e-6 * (stop->tv_usec - start->tv_usec); +} + +static double measure(void) +{ + long long i, iterations; + int result; + struct timeval start, stop; + double elapsed; + + add1(0, 0); /* prepare off-line */ + + i = 0; + iterations = 1000; + result = gettimeofday(&start, NULL); + assert(result == 0); + + while (1) { + for (; i < iterations; i++) { + add1(((int)i) & 0xaaaaaa, ((int)i) & 0x555555); + } + result = gettimeofday(&stop, NULL); + assert(result == 0); + + elapsed = time_delta(&stop, &start); + assert(elapsed >= 0.0); + if (elapsed > 2.5) + break; + iterations = iterations * 3 / 2; + } + + return elapsed / (double)iterations; +} + +static void *start_routine(void *arg) +{ + double t = measure(); + printf("time per call: %.3g\n", t); + +#ifdef PTEST_USE_THREAD + pthread_mutex_lock(&mutex1); + remaining -= 1; + if (!remaining) + pthread_cond_signal(&cond1); + pthread_mutex_unlock(&mutex1); +#endif + + return arg; +} + + +int main(void) +{ +#ifndef PTEST_USE_THREAD + start_routine(0); +#else + pthread_t th; + int i, status; + + add1(0, 0); /* this is the main thread */ + + remaining = PTEST_USE_THREAD; + for (i = 0; i < PTEST_USE_THREAD; i++) { + status = pthread_create(&th, NULL, start_routine, NULL); + assert(status == 0); + } + pthread_mutex_lock(&mutex1); + while (remaining) + pthread_cond_wait(&cond1, &mutex1); + pthread_mutex_unlock(&mutex1); +#endif + return 0; +} diff --git a/testing/embedding/perf.py b/testing/embedding/perf.py new file mode 100644 index 0000000..a8d20f4 --- /dev/null +++ b/testing/embedding/perf.py @@ -0,0 +1,21 @@ +import cffi + +ffi = cffi.FFI() + +ffi.embedding_api(""" + int add1(int, int); +""") + +ffi.embedding_init_code(r""" + from _perf_cffi import ffi + + @ffi.def_extern() + def add1(x, y): + return x + y +""") + +ffi.set_source("_perf_cffi", """ +""") + +fn = ffi.compile(verbose=True) +print('FILENAME: %s' % (fn,)) diff --git a/testing/embedding/test_basic.py b/testing/embedding/test_basic.py new file mode 100644 index 0000000..8463c3f --- /dev/null +++ b/testing/embedding/test_basic.py @@ -0,0 +1,207 @@ +import py +import sys, os, re +import shutil, subprocess, time +from testing.udir import udir +import cffi + + +local_dir = os.path.dirname(os.path.abspath(__file__)) +_link_error = '?' + +def check_lib_python_found(tmpdir): + global _link_error + if _link_error == '?': + ffi = cffi.FFI() + kwds = {} + ffi._apply_embedding_fix(kwds) + ffi.set_source("_test_lib_python_found", "", **kwds) + try: + ffi.compile(tmpdir=tmpdir, verbose=True) + except cffi.VerificationError as e: + _link_error = e + else: + _link_error = None + if _link_error: + py.test.skip(str(_link_error)) + + +def prefix_pythonpath(): + cffi_base = os.path.dirname(os.path.dirname(local_dir)) + pythonpath = org_env.get('PYTHONPATH', '').split(os.pathsep) + if cffi_base not in pythonpath: + pythonpath.insert(0, cffi_base) + return os.pathsep.join(pythonpath) + +def copy_away_env(): + global org_env + try: + org_env + except NameError: + org_env = os.environ.copy() + + +class EmbeddingTests: + _compiled_modules = {} + + def setup_method(self, meth): + check_lib_python_found(str(udir.ensure('embedding', dir=1))) + self._path = udir.join('embedding', meth.__name__) + if sys.platform == "win32" or sys.platform == "darwin": + self._compiled_modules.clear() # workaround + + def get_path(self): + return str(self._path.ensure(dir=1)) + + def _run_base(self, args, **kwds): + print('RUNNING:', args, kwds) + return subprocess.Popen(args, **kwds) + + def _run(self, args): + popen = self._run_base(args, cwd=self.get_path(), + stdout=subprocess.PIPE, + universal_newlines=True) + output = popen.stdout.read() + err = popen.wait() + if err: + raise OSError("popen failed with exit code %r: %r" % ( + err, args)) + print(output.rstrip()) + return output + + def prepare_module(self, name): + self.patch_environment() + if name not in self._compiled_modules: + path = self.get_path() + filename = '%s.py' % name + # NOTE: if you have an .egg globally installed with an older + # version of cffi, this will not work, because sys.path ends + # up with the .egg before the PYTHONPATH entries. I didn't + # find a solution to that: we could hack sys.path inside the + # script run here, but we can't hack it in the same way in + # execute(). + pathname = os.path.join(path, filename) + with open(pathname, 'w') as g: + g.write(''' +# https://bugs.python.org/issue23246 +import sys +if sys.platform == 'win32': + try: + import setuptools + except ImportError: + pass +''') + with open(os.path.join(local_dir, filename), 'r') as f: + g.write(f.read()) + + output = self._run([sys.executable, pathname]) + match = re.compile(r"\bFILENAME: (.+)").search(output) + assert match + dynamic_lib_name = match.group(1) + if sys.platform == 'win32': + assert dynamic_lib_name.endswith('_cffi.dll') + elif sys.platform == 'darwin': + assert dynamic_lib_name.endswith('_cffi.dylib') + else: + assert dynamic_lib_name.endswith('_cffi.so') + self._compiled_modules[name] = dynamic_lib_name + return self._compiled_modules[name] + + def compile(self, name, modules, opt=False, threads=False, defines={}): + path = self.get_path() + filename = '%s.c' % name + shutil.copy(os.path.join(local_dir, filename), path) + shutil.copy(os.path.join(local_dir, 'thread-test.h'), path) + import distutils.ccompiler + curdir = os.getcwd() + try: + os.chdir(self.get_path()) + c = distutils.ccompiler.new_compiler() + print('compiling %s with %r' % (name, modules)) + extra_preargs = [] + debug = True + if sys.platform == 'win32': + libfiles = [] + for m in modules: + m = os.path.basename(m) + assert m.endswith('.dll') + libfiles.append('Release\\%s.lib' % m[:-4]) + modules = libfiles + extra_preargs.append('/MANIFEST') + debug = False # you need to install extra stuff + # for this to work + elif threads: + extra_preargs.append('-pthread') + objects = c.compile([filename], macros=sorted(defines.items()), + debug=debug) + c.link_executable(objects + modules, name, extra_preargs=extra_preargs) + finally: + os.chdir(curdir) + + def patch_environment(self): + copy_away_env() + path = self.get_path() + # for libpypy-c.dll or Python27.dll + path = os.path.split(sys.executable)[0] + os.path.pathsep + path + env_extra = {'PYTHONPATH': prefix_pythonpath()} + if sys.platform == 'win32': + envname = 'PATH' + else: + envname = 'LD_LIBRARY_PATH' + libpath = org_env.get(envname) + if libpath: + libpath = path + os.path.pathsep + libpath + else: + libpath = path + env_extra[envname] = libpath + for key, value in sorted(env_extra.items()): + if os.environ.get(key) != value: + print('* setting env var %r to %r' % (key, value)) + os.environ[key] = value + + def execute(self, name): + path = self.get_path() + print('running %r in %r' % (name, path)) + executable_name = name + if sys.platform == 'win32': + executable_name = os.path.join(path, executable_name + '.exe') + else: + executable_name = os.path.join('.', executable_name) + popen = self._run_base([executable_name], cwd=path, + stdout=subprocess.PIPE, + universal_newlines=True) + result = popen.stdout.read() + err = popen.wait() + if err: + raise OSError("%r failed with exit code %r" % (name, err)) + return result + + +class TestBasic(EmbeddingTests): + def test_empty(self): + empty_cffi = self.prepare_module('empty') + + def test_basic(self): + add1_cffi = self.prepare_module('add1') + self.compile('add1-test', [add1_cffi]) + output = self.execute('add1-test') + assert output == ("preparing...\n" + "adding 40 and 2\n" + "adding 100 and -5\n" + "got: 42 95\n") + + def test_two_modules(self): + add1_cffi = self.prepare_module('add1') + add2_cffi = self.prepare_module('add2') + self.compile('add2-test', [add1_cffi, add2_cffi]) + output = self.execute('add2-test') + assert output == ("preparing...\n" + "adding 40 and 2\n" + "prepADD2\n" + "adding 100 and -5 and -20\n" + "got: 42 75\n") + + def test_init_time_error(self): + initerror_cffi = self.prepare_module('initerror') + self.compile('add1-test', [initerror_cffi]) + output = self.execute('add1-test') + assert output == "got: 0 0\n" # plus lots of info to stderr diff --git a/testing/embedding/test_performance.py b/testing/embedding/test_performance.py new file mode 100644 index 0000000..f9f2605 --- /dev/null +++ b/testing/embedding/test_performance.py @@ -0,0 +1,52 @@ +import sys +from testing.embedding.test_basic import EmbeddingTests + +if sys.platform == 'win32': + import py + py.test.skip("written with POSIX functions") + + +class TestPerformance(EmbeddingTests): + def test_perf_single_threaded(self): + perf_cffi = self.prepare_module('perf') + self.compile('perf-test', [perf_cffi], opt=True) + output = self.execute('perf-test') + print('='*79) + print(output.rstrip()) + print('='*79) + + def test_perf_in_1_thread(self): + perf_cffi = self.prepare_module('perf') + self.compile('perf-test', [perf_cffi], opt=True, threads=True, + defines={'PTEST_USE_THREAD': '1'}) + output = self.execute('perf-test') + print('='*79) + print(output.rstrip()) + print('='*79) + + def test_perf_in_2_threads(self): + perf_cffi = self.prepare_module('perf') + self.compile('perf-test', [perf_cffi], opt=True, threads=True, + defines={'PTEST_USE_THREAD': '2'}) + output = self.execute('perf-test') + print('='*79) + print(output.rstrip()) + print('='*79) + + def test_perf_in_4_threads(self): + perf_cffi = self.prepare_module('perf') + self.compile('perf-test', [perf_cffi], opt=True, threads=True, + defines={'PTEST_USE_THREAD': '4'}) + output = self.execute('perf-test') + print('='*79) + print(output.rstrip()) + print('='*79) + + def test_perf_in_8_threads(self): + perf_cffi = self.prepare_module('perf') + self.compile('perf-test', [perf_cffi], opt=True, threads=True, + defines={'PTEST_USE_THREAD': '8'}) + output = self.execute('perf-test') + print('='*79) + print(output.rstrip()) + print('='*79) diff --git a/testing/embedding/test_recursive.py b/testing/embedding/test_recursive.py new file mode 100644 index 0000000..b85e7ed --- /dev/null +++ b/testing/embedding/test_recursive.py @@ -0,0 +1,15 @@ +from testing.embedding.test_basic import EmbeddingTests + + +class TestRecursive(EmbeddingTests): + def test_recursive(self): + add_recursive_cffi = self.prepare_module('add_recursive') + self.compile('add_recursive-test', [add_recursive_cffi]) + output = self.execute('add_recursive-test') + assert output == ("preparing REC\n" + "some_callback(400)\n" + "adding 400 and 9\n" + "<<< 409 >>>\n" + "adding 40 and 2\n" + "adding 100 and -5\n" + "got: 42 95\n") diff --git a/testing/embedding/test_thread.py b/testing/embedding/test_thread.py new file mode 100644 index 0000000..1895076 --- /dev/null +++ b/testing/embedding/test_thread.py @@ -0,0 +1,61 @@ +from testing.embedding.test_basic import EmbeddingTests + + +class TestThread(EmbeddingTests): + def test_first_calls_in_parallel(self): + add1_cffi = self.prepare_module('add1') + self.compile('thread1-test', [add1_cffi], threads=True) + for i in range(20): + output = self.execute('thread1-test') + assert output == ("starting\n" + "preparing...\n" + + "adding 40 and 2\n" * 10 + + "done\n") + + def _take_out(self, text, content): + assert content in text + i = text.index(content) + return text[:i] + text[i+len(content):] + + def test_init_different_modules_in_different_threads(self): + add1_cffi = self.prepare_module('add1') + add2_cffi = self.prepare_module('add2') + self.compile('thread2-test', [add1_cffi, add2_cffi], threads=True) + output = self.execute('thread2-test') + output = self._take_out(output, "preparing") + output = self._take_out(output, ".") + output = self._take_out(output, ".") + # at least the 3rd dot should be after everything from ADD2 + assert output == ("starting\n" + "prepADD2\n" + "adding 1000 and 200 and 30\n" + ".\n" + "adding 40 and 2\n" + "done\n") + + def test_alt_issue(self): + add1_cffi = self.prepare_module('add1') + add2_cffi = self.prepare_module('add2') + self.compile('thread2-test', [add1_cffi, add2_cffi], + threads=True, defines={'T2TEST_AGAIN_ADD1': '1'}) + output = self.execute('thread2-test') + output = self._take_out(output, "adding 40 and 2\n") + assert output == ("starting\n" + "preparing...\n" + "adding -1 and -1\n" + "prepADD2\n" + "adding 1000 and 200 and 30\n" + "done\n") + + def test_load_in_parallel_more(self): + add2_cffi = self.prepare_module('add2') + add3_cffi = self.prepare_module('add3') + self.compile('thread3-test', [add2_cffi, add3_cffi], threads=True) + for i in range(150): + output = self.execute('thread3-test') + for j in range(10): + output = self._take_out(output, "adding 40 and 2 and 100\n") + output = self._take_out(output, "adding 1000, 200, 30, 4\n") + assert output == ("starting\n" + "prepADD2\n" + "done\n") diff --git a/testing/embedding/test_tlocal.py b/testing/embedding/test_tlocal.py new file mode 100644 index 0000000..6e7c5af --- /dev/null +++ b/testing/embedding/test_tlocal.py @@ -0,0 +1,10 @@ +from testing.embedding.test_basic import EmbeddingTests + + +class TestThreadLocal(EmbeddingTests): + def test_thread_local(self): + tlocal_cffi = self.prepare_module('tlocal') + self.compile('tlocal-test', [tlocal_cffi], threads=True) + for i in range(10): + output = self.execute('tlocal-test') + assert output == "done\n" diff --git a/testing/embedding/thread-test.h b/testing/embedding/thread-test.h new file mode 100644 index 0000000..f66cf70 --- /dev/null +++ b/testing/embedding/thread-test.h @@ -0,0 +1,96 @@ +/************************************************************/ +#ifndef _MSC_VER +/************************************************************/ + + +#include <pthread.h> + +/* don't include <semaphore.h>, it is not available on OS/X */ + +typedef struct { + pthread_mutex_t mutex1; + pthread_cond_t cond1; + unsigned int value; +} sem_t; + +static int sem_init(sem_t *sem, int pshared, unsigned int value) +{ + assert(pshared == 0); + sem->value = value; + return (pthread_mutex_init(&sem->mutex1, NULL) || + pthread_cond_init(&sem->cond1, NULL)); +} + +static int sem_post(sem_t *sem) +{ + pthread_mutex_lock(&sem->mutex1); + sem->value += 1; + pthread_cond_signal(&sem->cond1); + pthread_mutex_unlock(&sem->mutex1); + return 0; +} + +static int sem_wait(sem_t *sem) +{ + pthread_mutex_lock(&sem->mutex1); + while (sem->value == 0) + pthread_cond_wait(&sem->cond1, &sem->mutex1); + sem->value -= 1; + pthread_mutex_unlock(&sem->mutex1); + return 0; +} + + +/************************************************************/ +#else +/************************************************************/ + + +/* Very quick and dirty, just what I need for these tests. + Don't use directly in any real code! +*/ + +#include <Windows.h> +#include <assert.h> + +typedef HANDLE sem_t; +typedef HANDLE pthread_t; + +static int sem_init(sem_t *sem, int pshared, unsigned int value) +{ + assert(pshared == 0); + assert(value == 0); + *sem = CreateSemaphore(NULL, 0, 999, NULL); + return *sem ? 0 : -1; +} + +static int sem_post(sem_t *sem) +{ + return ReleaseSemaphore(*sem, 1, NULL) ? 0 : -1; +} + +static int sem_wait(sem_t *sem) +{ + WaitForSingleObject(*sem, INFINITE); + return 0; +} + +static DWORD WINAPI myThreadProc(LPVOID lpParameter) +{ + void *(* start_routine)(void *) = (void *(*)(void *))lpParameter; + start_routine(NULL); + return 0; +} + +static int pthread_create(pthread_t *thread, void *attr, + void *start_routine(void *), void *arg) +{ + assert(arg == NULL); + *thread = CreateThread(NULL, 0, myThreadProc, start_routine, 0, NULL); + return *thread ? 0 : -1; +} + + +/************************************************************/ +#endif +/************************************************************/ diff --git a/testing/embedding/thread1-test.c b/testing/embedding/thread1-test.c new file mode 100644 index 0000000..70bb861 --- /dev/null +++ b/testing/embedding/thread1-test.c @@ -0,0 +1,43 @@ +#include <stdio.h> +#include <assert.h> +#include "thread-test.h" + +#define NTHREADS 10 + + +extern int add1(int, int); + +static sem_t done; + + +static void *start_routine(void *arg) +{ + int x, status; + x = add1(40, 2); + assert(x == 42); + + status = sem_post(&done); + assert(status == 0); + + return arg; +} + +int main(void) +{ + pthread_t th; + int i, status = sem_init(&done, 0, 0); + assert(status == 0); + + printf("starting\n"); + fflush(stdout); + for (i = 0; i < NTHREADS; i++) { + status = pthread_create(&th, NULL, start_routine, NULL); + assert(status == 0); + } + for (i = 0; i < NTHREADS; i++) { + status = sem_wait(&done); + assert(status == 0); + } + printf("done\n"); + return 0; +} diff --git a/testing/embedding/thread2-test.c b/testing/embedding/thread2-test.c new file mode 100644 index 0000000..62f5ec8 --- /dev/null +++ b/testing/embedding/thread2-test.c @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <assert.h> +#include "thread-test.h" + +extern int add1(int, int); +extern int add2(int, int, int); + +static sem_t done; + + +static void *start_routine_1(void *arg) +{ + int x, status; + x = add1(40, 2); + assert(x == 42); + + status = sem_post(&done); + assert(status == 0); + + return arg; +} + +static void *start_routine_2(void *arg) +{ + int x, status; +#ifdef T2TEST_AGAIN_ADD1 + add1(-1, -1); +#endif + x = add2(1000, 200, 30); + assert(x == 1230); + + status = sem_post(&done); + assert(status == 0); + + return arg; +} + +int main(void) +{ + pthread_t th; + int i, status = sem_init(&done, 0, 0); + assert(status == 0); + + printf("starting\n"); + fflush(stdout); + status = pthread_create(&th, NULL, start_routine_1, NULL); + assert(status == 0); + status = pthread_create(&th, NULL, start_routine_2, NULL); + assert(status == 0); + + for (i = 0; i < 2; i++) { + status = sem_wait(&done); + assert(status == 0); + } + printf("done\n"); + return 0; +} diff --git a/testing/embedding/thread3-test.c b/testing/embedding/thread3-test.c new file mode 100644 index 0000000..69ada27 --- /dev/null +++ b/testing/embedding/thread3-test.c @@ -0,0 +1,56 @@ +#include <stdio.h> +#include <assert.h> +#include "thread-test.h" + +extern int add2(int, int, int); +extern int add3(int, int, int, int); + +static sem_t done; + + +static void *start_routine_2(void *arg) +{ + int x, status; + x = add2(40, 2, 100); + assert(x == 142); + + status = sem_post(&done); + assert(status == 0); + + return arg; +} + +static void *start_routine_3(void *arg) +{ + int x, status; + x = add3(1000, 200, 30, 4); + assert(x == 1234); + + status = sem_post(&done); + assert(status == 0); + + return arg; +} + +int main(void) +{ + pthread_t th; + int i, status = sem_init(&done, 0, 0); + assert(status == 0); + + printf("starting\n"); + fflush(stdout); + for (i = 0; i < 10; i++) { + status = pthread_create(&th, NULL, start_routine_2, NULL); + assert(status == 0); + status = pthread_create(&th, NULL, start_routine_3, NULL); + assert(status == 0); + } + for (i = 0; i < 20; i++) { + status = sem_wait(&done); + assert(status == 0); + } + printf("done\n"); + fflush(stdout); /* this is occasionally needed on Windows */ + return 0; +} diff --git a/testing/embedding/tlocal-test.c b/testing/embedding/tlocal-test.c new file mode 100644 index 0000000..b78a03d --- /dev/null +++ b/testing/embedding/tlocal-test.c @@ -0,0 +1,47 @@ +#include <stdio.h> +#include <assert.h> +#include "thread-test.h" + +#define NTHREADS 10 + + +extern int add1(int, int); + +static sem_t done; + + +static void *start_routine(void *arg) +{ + int i, x, expected, status; + + expected = add1(40, 2); + assert((expected % 1000) == 42); + + for (i=0; i<10; i++) { + x = add1(50, i); + assert(x == expected + 8 + i); + } + + status = sem_post(&done); + assert(status == 0); + + return arg; +} + +int main(void) +{ + pthread_t th; + int i, status = sem_init(&done, 0, 0); + assert(status == 0); + + for (i = 0; i < NTHREADS; i++) { + status = pthread_create(&th, NULL, start_routine, NULL); + assert(status == 0); + } + for (i = 0; i < NTHREADS; i++) { + status = sem_wait(&done); + assert(status == 0); + } + printf("done\n"); + return 0; +} diff --git a/testing/embedding/tlocal.py b/testing/embedding/tlocal.py new file mode 100644 index 0000000..7800dff --- /dev/null +++ b/testing/embedding/tlocal.py @@ -0,0 +1,33 @@ +import cffi + +ffi = cffi.FFI() + +ffi.embedding_api(""" + int add1(int, int); +""") + +ffi.embedding_init_code(r""" + from _tlocal_cffi import ffi + import itertools + try: + import thread + g_seen = itertools.count().next + except ImportError: + import _thread as thread # py3 + g_seen = itertools.count().__next__ + tloc = thread._local() + + @ffi.def_extern() + def add1(x, y): + try: + num = tloc.num + except AttributeError: + num = tloc.num = g_seen() * 1000 + return x + y + num +""") + +ffi.set_source("_tlocal_cffi", """ +""") + +fn = ffi.compile(verbose=True) +print('FILENAME: %s' % (fn,)) |