From 0153159e67bf4247c4402a1a6e717819372c9337 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 17 Sep 2007 03:28:34 +0000 Subject: Add a bunch of GIL release/acquire points in tp_print implementations and for PyObject_Print(). Closes issue #1164. --- Misc/NEWS | 5 +++++ Modules/_collectionsmodule.c | 19 ++++++++++++++++++- Objects/boolobject.c | 2 ++ Objects/complexobject.c | 2 ++ Objects/dictobject.c | 13 ++++++++++++- Objects/fileobject.c | 2 ++ Objects/floatobject.c | 2 ++ Objects/intobject.c | 5 ++++- Objects/listobject.c | 11 ++++++++++- Objects/object.c | 4 ++++ Objects/setobject.c | 8 ++++++++ Objects/stringobject.c | 12 ++++++++++-- Objects/tupleobject.c | 12 ++++++++++-- 13 files changed, 89 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 73495db..e3869d9 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,11 @@ What's New in Python 2.6 alpha 1? Core and builtins ----------------- +- Issue #1164: It was possible to trigger deadlock when using the 'print' + statement to write to a file since the GIL was not released as needed. Now + PyObject_Print() does the right thing along with various tp_print + implementations of the built-in types and those in the collections module. + - Issue #1147: Exceptions were directly allowing string exceptions in their throw() method even though string exceptions no longer allowed. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 7f5e2ae..ea68f80 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -652,7 +652,9 @@ deque_tp_print(PyObject *deque, FILE *fp, int flags) if (i != 0) { if (i < 0) return i; + Py_BEGIN_ALLOW_THREADS fputs("[...]", fp); + Py_END_ALLOW_THREADS return 0; } @@ -660,9 +662,13 @@ deque_tp_print(PyObject *deque, FILE *fp, int flags) if (it == NULL) return -1; + Py_BEGIN_ALLOW_THREADS fputs("deque([", fp); + Py_END_ALLOW_THREADS while ((item = PyIter_Next(it)) != NULL) { + Py_BEGIN_ALLOW_THREADS fputs(emit, fp); + Py_END_ALLOW_THREADS emit = separator; if (PyObject_Print(item, fp, 0) != 0) { Py_DECREF(item); @@ -676,7 +682,9 @@ deque_tp_print(PyObject *deque, FILE *fp, int flags) Py_DECREF(it); if (PyErr_Occurred()) return -1; + Py_BEGIN_ALLOW_THREADS fputs("])", fp); + Py_END_ALLOW_THREADS return 0; } @@ -1190,15 +1198,24 @@ static int defdict_print(defdictobject *dd, FILE *fp, int flags) { int sts; + Py_BEGIN_ALLOW_THREADS fprintf(fp, "defaultdict("); - if (dd->default_factory == NULL) + Py_END_ALLOW_THREADS + if (dd->default_factory == NULL) { + Py_BEGIN_ALLOW_THREADS fprintf(fp, "None"); + Py_END_ALLOW_THREADS + } else { PyObject_Print(dd->default_factory, fp, 0); } + Py_BEGIN_ALLOW_THREADS fprintf(fp, ", "); + Py_END_ALLOW_THREADS sts = PyDict_Type.tp_print((PyObject *)dd, fp, 0); + Py_BEGIN_ALLOW_THREADS fprintf(fp, ")"); + Py_END_ALLOW_THREADS return sts; } diff --git a/Objects/boolobject.c b/Objects/boolobject.c index 40f860b..fd73d28 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -7,7 +7,9 @@ static int bool_print(PyBoolObject *self, FILE *fp, int flags) { + Py_BEGIN_ALLOW_THREADS fputs(self->ob_ival == 0 ? "False" : "True", fp); + Py_END_ALLOW_THREADS return 0; } diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 6d1dbde..7de4d5c 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -341,7 +341,9 @@ complex_print(PyComplexObject *v, FILE *fp, int flags) char buf[100]; complex_to_buf(buf, sizeof(buf), v, (flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR); + Py_BEGIN_ALLOW_THREADS fputs(buf, fp); + Py_END_ALLOW_THREADS return 0; } diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 30b3598..aa61e8c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -867,11 +867,15 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags) if (status != 0) { if (status < 0) return status; + Py_BEGIN_ALLOW_THREADS fprintf(fp, "{...}"); + Py_END_ALLOW_THREADS return 0; } + Py_BEGIN_ALLOW_THREADS fprintf(fp, "{"); + Py_END_ALLOW_THREADS any = 0; for (i = 0; i <= mp->ma_mask; i++) { dictentry *ep = mp->ma_table + i; @@ -880,14 +884,19 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags) /* Prevent PyObject_Repr from deleting value during key format */ Py_INCREF(pvalue); - if (any++ > 0) + if (any++ > 0) { + Py_BEGIN_ALLOW_THREADS fprintf(fp, ", "); + Py_END_ALLOW_THREADS + } if (PyObject_Print((PyObject *)ep->me_key, fp, 0)!=0) { Py_DECREF(pvalue); Py_ReprLeave((PyObject*)mp); return -1; } + Py_BEGIN_ALLOW_THREADS fprintf(fp, ": "); + Py_END_ALLOW_THREADS if (PyObject_Print(pvalue, fp, 0) != 0) { Py_DECREF(pvalue); Py_ReprLeave((PyObject*)mp); @@ -896,7 +905,9 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags) Py_DECREF(pvalue); } } + Py_BEGIN_ALLOW_THREADS fprintf(fp, "}"); + Py_END_ALLOW_THREADS Py_ReprLeave((PyObject*)mp); return 0; } diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 4c5b37d..16786f8 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -2241,7 +2241,9 @@ PyFile_WriteString(const char *s, PyObject *f) err_closed(); return -1; } + Py_BEGIN_ALLOW_THREADS fputs(s, fp); + Py_END_ALLOW_THREADS return 0; } else if (!PyErr_Occurred()) { diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 4dd7d03..bf9b172 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -334,7 +334,9 @@ float_print(PyFloatObject *v, FILE *fp, int flags) char buf[100]; format_float(buf, sizeof(buf), v, (flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR); + Py_BEGIN_ALLOW_THREADS fputs(buf, fp); + Py_END_ALLOW_THREADS return 0; } diff --git a/Objects/intobject.c b/Objects/intobject.c index c4aeed5..364947e 100644 --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -425,7 +425,10 @@ static int int_print(PyIntObject *v, FILE *fp, int flags) /* flags -- not used but required by interface */ { - fprintf(fp, "%ld", v->ob_ival); + long int_val = v->ob_ival; + Py_BEGIN_ALLOW_THREADS + fprintf(fp, "%ld", int_val); + Py_END_ALLOW_THREADS return 0; } diff --git a/Objects/listobject.c b/Objects/listobject.c index 92bad8c..a3fa983 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -282,19 +282,28 @@ list_print(PyListObject *op, FILE *fp, int flags) if (rc != 0) { if (rc < 0) return rc; + Py_BEGIN_ALLOW_THREADS fprintf(fp, "[...]"); + Py_END_ALLOW_THREADS return 0; } + Py_BEGIN_ALLOW_THREADS fprintf(fp, "["); + Py_END_ALLOW_THREADS for (i = 0; i < Py_Size(op); i++) { - if (i > 0) + if (i > 0) { + Py_BEGIN_ALLOW_THREADS fprintf(fp, ", "); + Py_END_ALLOW_THREADS + } if (PyObject_Print(op->ob_item[i], fp, 0) != 0) { Py_ReprLeave((PyObject *)op); return -1; } } + Py_BEGIN_ALLOW_THREADS fprintf(fp, "]"); + Py_END_ALLOW_THREADS Py_ReprLeave((PyObject *)op); return 0; } diff --git a/Objects/object.c b/Objects/object.c index 4330b08..0651d6b6 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -279,14 +279,18 @@ internal_print(PyObject *op, FILE *fp, int flags, int nesting) #endif clearerr(fp); /* Clear any previous error condition */ if (op == NULL) { + Py_BEGIN_ALLOW_THREADS fprintf(fp, ""); + Py_END_ALLOW_THREADS } else { if (op->ob_refcnt <= 0) /* XXX(twouters) cast refcount to long until %zd is universally available */ + Py_BEGIN_ALLOW_THREADS fprintf(fp, "", (long)op->ob_refcnt, op); + Py_END_ALLOW_THREADS else if (Py_Type(op)->tp_print == NULL) { PyObject *s; if (flags & Py_PRINT_RAW) diff --git a/Objects/setobject.c b/Objects/setobject.c index f0a11ca..025a79b 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -577,20 +577,28 @@ set_tp_print(PySetObject *so, FILE *fp, int flags) if (status != 0) { if (status < 0) return status; + Py_BEGIN_ALLOW_THREADS fprintf(fp, "%s(...)", so->ob_type->tp_name); + Py_END_ALLOW_THREADS return 0; } + Py_BEGIN_ALLOW_THREADS fprintf(fp, "%s([", so->ob_type->tp_name); + Py_END_ALLOW_THREADS while (set_next(so, &pos, &entry)) { + Py_BEGIN_ALLOW_THREADS fputs(emit, fp); + Py_END_ALLOW_THREADS emit = separator; if (PyObject_Print(entry->key, fp, 0) != 0) { Py_ReprLeave((PyObject*)so); return -1; } } + Py_BEGIN_ALLOW_THREADS fputs("])", fp); + Py_END_ALLOW_THREADS Py_ReprLeave((PyObject*)so); return 0; } diff --git a/Objects/stringobject.c b/Objects/stringobject.c index fb7548d..22b50d5 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -788,7 +788,7 @@ PyString_AsStringAndSize(register PyObject *obj, static int string_print(PyStringObject *op, FILE *fp, int flags) { - Py_ssize_t i; + Py_ssize_t i, str_len; char c; int quote; @@ -806,6 +806,7 @@ string_print(PyStringObject *op, FILE *fp, int flags) if (flags & Py_PRINT_RAW) { char *data = op->ob_sval; Py_ssize_t size = Py_Size(op); + Py_BEGIN_ALLOW_THREADS while (size > INT_MAX) { /* Very long strings cannot be written atomically. * But don't write exactly INT_MAX bytes at a time @@ -821,6 +822,7 @@ string_print(PyStringObject *op, FILE *fp, int flags) #else fwrite(data, 1, (int)size, fp); #endif + Py_END_ALLOW_THREADS return 0; } @@ -830,8 +832,13 @@ string_print(PyStringObject *op, FILE *fp, int flags) !memchr(op->ob_sval, '"', Py_Size(op))) quote = '"'; + str_len = Py_Size(op); + Py_BEGIN_ALLOW_THREADS fputc(quote, fp); - for (i = 0; i < Py_Size(op); i++) { + for (i = 0; i < str_len; i++) { + /* Since strings are immutable and the caller should have a + reference, accessing the interal buffer should not be an issue + with the GIL released. */ c = op->ob_sval[i]; if (c == quote || c == '\\') fprintf(fp, "\\%c", c); @@ -847,6 +854,7 @@ string_print(PyStringObject *op, FILE *fp, int flags) fputc(c, fp); } fputc(quote, fp); + Py_END_ALLOW_THREADS return 0; } diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index f1e3aee..b85762a 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -188,16 +188,24 @@ static int tupleprint(PyTupleObject *op, FILE *fp, int flags) { Py_ssize_t i; + Py_BEGIN_ALLOW_THREADS fprintf(fp, "("); + Py_END_ALLOW_THREADS for (i = 0; i < Py_Size(op); i++) { - if (i > 0) + if (i > 0) { + Py_BEGIN_ALLOW_THREADS fprintf(fp, ", "); + Py_END_ALLOW_THREADS + } if (PyObject_Print(op->ob_item[i], fp, 0) != 0) return -1; } - if (Py_Size(op) == 1) + i = Py_Size(op); + Py_BEGIN_ALLOW_THREADS + if (i == 1) fprintf(fp, ","); fprintf(fp, ")"); + Py_END_ALLOW_THREADS return 0; } -- cgit v0.12