diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 75bac142f4fd62ad5e3720385695c3986beb8d9d..3a234a6ba3aef374acb6bb420774023edd5f5d17 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -6224,7 +6224,8 @@ class ParallelWithBlockNode(ParallelStatNode): code.put("#pragma omp parallel ") if self.privates: - privates = [e.cname for e in self.privates] + privates = [e.cname for e in self.privates + if not e.type.is_pyobject] code.put('private(%s)' % ', '.join(privates)) self.privatization_insertion_point = code.insertion_point() @@ -6239,6 +6240,9 @@ class ParallelWithBlockNode(ParallelStatNode): self.trap_parallel_exit(code) code.end_block() # end parallel block + # After the parallel block all privates are undefined + self.initialize_privates_to_nan(code) + continue_ = code.label_used(code.continue_label) break_ = code.label_used(code.break_label) @@ -6489,7 +6493,9 @@ class ParallelRangeNode(ParallelStatNode): else: if entry == self.target.entry: code.put(" firstprivate(%s)" % entry.cname) - code.put(" lastprivate(%s)" % entry.cname) + + if not entry.type.is_pyobject: + code.put(" lastprivate(%s)" % entry.cname) if self.schedule: code.put(" schedule(%s)" % self.schedule) @@ -7576,6 +7582,10 @@ proto=""" #endif """) +init_threads = UtilityCode( + init="PyEval_InitThreads();\n", +) + #------------------------------------------------------------------------------------ # Note that cPython ignores PyTrace_EXCEPTION, diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index cc4739723c43407239ec00d45c67efd6e347f40e..03bea8fc32966410ad3f3da7d9159a29fbdc2325 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -650,6 +650,8 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): self.wrong_scope_error(node.pos, key, 'module') del node.directive_comments[key] + self.module_scope = node.scope + directives = copy.deepcopy(Options.directive_defaults) directives.update(copy.deepcopy(self.compilation_directive_defaults)) directives.update(node.directive_comments) @@ -684,6 +686,8 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): directive[-1] not in self.valid_parallel_directives): error(pos, "No such directive: %s" % full_name) + self.module_scope.use_utility_code(Nodes.init_threads) + return result def visit_CImportStatNode(self, node): @@ -699,6 +703,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): self.cython_module_names.add(u"cython") self.parallel_directives[ u"cython.parallel"] = node.module_name + self.module_scope.use_utility_code(Nodes.init_threads) elif node.as_name: self.directive_names[node.as_name] = node.module_name[7:] else: diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 9fdb59b67b72d546da1933539ba727a915a4b166..b1fd99f797e7cf5ea8bff003eed820abda47d14b 100755 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -387,9 +387,6 @@ class PyObjectType(PyrexType): else: return cname - def invalid_value(self): - return "1" - class BuiltinObjectType(PyObjectType): # objstruct_cname string Name of PyObject struct diff --git a/tests/run/sequential_parallel.pyx b/tests/run/sequential_parallel.pyx index 4d5413aa011be06b8fbade3c9b7306891d39ae15..2920135a60c0ed45208720cfd31fb0316adc4122 100644 --- a/tests/run/sequential_parallel.pyx +++ b/tests/run/sequential_parallel.pyx @@ -233,8 +233,14 @@ def test_nan_init(): raise Exception("One of the values was not initialized to a maximum " "or NaN value") + c1 = 20 + with nogil, cython.parallel.parallel(): + c1 = 16 + + assert c1 not in (16, 20), c1 + cdef void nogil_print(char *s) with gil: - print s + print s.decode('ascii') def test_else_clause(): """ @@ -343,3 +349,64 @@ def test_return(): """ print parallel_return() +def test_parallel_exceptions(): + """ + >>> test_parallel_exceptions() + ('I am executed first', 0) + ('propagate me',) 0 + """ + cdef int i, j, sum = 0 + + mylist = [] + + try: + for i in prange(10, nogil=True): + try: + for j in prange(10): + with gil: + raise Exception("propagate me") + + sum += i * j + sum += i + finally: + with gil: + mylist.append(("I am executed first", sum)) + except Exception, e: + print mylist[0] + print e.args, sum + +def test_parallel_with_gil_return(): + """ + >>> test_parallel_with_gil_return() + True + 45 + """ + cdef int i, sum = 0 + + for i in prange(10, nogil=True): + with gil: + obj = i + sum += obj + + print obj in range(10) + + with nogil, cython.parallel.parallel(): + with gil: + return sum + +def test_parallel_with_gil_continue(): + """ + >>> test_parallel_with_gil_continue() + 20 + """ + cdef int i, sum = 0 + + for i in prange(10, nogil=True): + with cython.parallel.parallel(): + with gil: + if i % 2: + continue + + sum += i + + print sum diff --git a/tests/run/with_gil.pyx b/tests/run/with_gil.pyx index 908d9cb8899d06d8db1461c3f81d9accc4c16e1f..1c2567fba926ca3a0c4e14885b173fc392cfbf33 100644 --- a/tests/run/with_gil.pyx +++ b/tests/run/with_gil.pyx @@ -202,7 +202,7 @@ def test_loops_and_boxing(): with nogil: with gil: - print string.decode('ASCII') + print string.decode('ascii') for c in string[4:]: print "%c" % c else: