From 973b3155c43777853725cc5c99d3f807d5cf5c67 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Mon, 14 Jan 2019 11:23:46 +0100 Subject: [PATCH] Fix deadlock on Travis with --parallel. We cannot throw any exception or call exit() in an async task, or Python deadlocks. Catch any errors and propagate them to top thread. --- test_shaders.py | 60 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/test_shaders.py b/test_shaders.py index 045c2551..18d8a42b 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -129,7 +129,7 @@ def validate_shader_msl(shader, opt): raise except subprocess.CalledProcessError: print('Error compiling Metal shader: ' + msl_path) - sys.exit(1) + raise RuntimeError('Failed to compile Metal shader') def cross_compile_msl(shader, spirv, opt): spirv_path = create_temporary() @@ -201,12 +201,15 @@ def validate_shader_hlsl(shader, force_no_external_validation): subprocess.check_call(['fxc', '-nologo', shader_model_hlsl(shader), win_path]) except OSError as oe: if (oe.errno != errno.ENOENT): # Ignore not found errors + print('Failed to run FXC.') + ignore_fxc = True raise else: + print('Could not find FXC.') ignore_fxc = True except subprocess.CalledProcessError: print('Failed compiling HLSL shader:', shader, 'with FXC.') - sys.exit(1) + raise RuntimeError('Failed compiling HLSL shader') def shader_to_sm(shader): if '.sm60.' in shader: @@ -382,7 +385,8 @@ def regression_check_reflect(shader, json_file, update, keep, opt): # Otherwise, fail the test. Keep the shader file around so we can inspect. if not keep: remove_file(json_file) - sys.exit(1) + + raise RuntimeError('Does not match reference') else: remove_file(json_file) else: @@ -417,7 +421,7 @@ def regression_check(shader, glsl, update, keep, opt): # Otherwise, fail the test. Keep the shader file around so we can inspect. if not keep: remove_file(glsl) - sys.exit(1) + raise RuntimeError('Does not match reference') else: remove_file(glsl) else: @@ -533,14 +537,18 @@ def test_shader_reflect(stats, shader, update, keep, opt): remove_file(spirv) def test_shader_file(relpath, stats, shader_dir, update, keep, opt, force_no_external_validation, backend): - if backend == 'msl': - test_shader_msl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation) - elif backend == 'hlsl': - test_shader_hlsl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation) - elif backend == 'reflect': - test_shader_reflect(stats, (shader_dir, relpath), update, keep, opt) - else: - test_shader(stats, (shader_dir, relpath), update, keep, opt) + try: + if backend == 'msl': + test_shader_msl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation) + elif backend == 'hlsl': + test_shader_hlsl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation) + elif backend == 'reflect': + test_shader_reflect(stats, (shader_dir, relpath), update, keep, opt) + else: + test_shader(stats, (shader_dir, relpath), update, keep, opt) + return None + except Exception as e: + return e def test_shaders_helper(stats, backend, args): all_files = [] @@ -555,17 +563,27 @@ def test_shaders_helper(stats, backend, args): # at this point we need to switch to explicit arguments if args.parallel: pool = multiprocessing.Pool(multiprocessing.cpu_count()) - pool.map(partial(test_shader_file, - stats = stats, - shader_dir = args.folder, - update = args.update, - keep = args.keep, - opt = args.opt, - force_no_external_validation = args.force_no_external_validation, - backend = backend), all_files) + + results = [] + for f in all_files: + results.append(pool.apply_async(test_shader_file, + args = (f, stats, + args.folder, args.update, args.keep, args.opt, args.force_no_external_validation, + backend))) + + for res in results: + error = res.get() + if error is not None: + pool.close() + pool.join() + print('Error:', error) + sys.exit(1) else: for i in all_files: - test_shader_file(i, stats, args.folder, args.update, args.keep, args.opt, args.force_no_external_validation, backend) + e = test_shader_file(i, stats, args.folder, args.update, args.keep, args.opt, args.force_no_external_validation, backend) + if e is not None: + print('Error:', e) + sys.exit(1) def test_shaders(backend, args): if args.malisc: