Add a bunch of GIL release/acquire points in tp_print implementations and for
PyObject_Print(). Closes issue #1164.
This commit is contained in:
parent
d36a60e1e3
commit
0153159e67
|
@ -12,6 +12,11 @@ What's New in Python 2.6 alpha 1?
|
||||||
Core and builtins
|
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
|
- Issue #1147: Exceptions were directly allowing string exceptions in their
|
||||||
throw() method even though string exceptions no longer allowed.
|
throw() method even though string exceptions no longer allowed.
|
||||||
|
|
||||||
|
|
|
@ -652,7 +652,9 @@ deque_tp_print(PyObject *deque, FILE *fp, int flags)
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
return i;
|
return i;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs("[...]", fp);
|
fputs("[...]", fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,9 +662,13 @@ deque_tp_print(PyObject *deque, FILE *fp, int flags)
|
||||||
if (it == NULL)
|
if (it == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs("deque([", fp);
|
fputs("deque([", fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
while ((item = PyIter_Next(it)) != NULL) {
|
while ((item = PyIter_Next(it)) != NULL) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs(emit, fp);
|
fputs(emit, fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
emit = separator;
|
emit = separator;
|
||||||
if (PyObject_Print(item, fp, 0) != 0) {
|
if (PyObject_Print(item, fp, 0) != 0) {
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
|
@ -676,7 +682,9 @@ deque_tp_print(PyObject *deque, FILE *fp, int flags)
|
||||||
Py_DECREF(it);
|
Py_DECREF(it);
|
||||||
if (PyErr_Occurred())
|
if (PyErr_Occurred())
|
||||||
return -1;
|
return -1;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs("])", fp);
|
fputs("])", fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,15 +1198,24 @@ static int
|
||||||
defdict_print(defdictobject *dd, FILE *fp, int flags)
|
defdict_print(defdictobject *dd, FILE *fp, int flags)
|
||||||
{
|
{
|
||||||
int sts;
|
int sts;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "defaultdict(");
|
fprintf(fp, "defaultdict(");
|
||||||
if (dd->default_factory == NULL)
|
Py_END_ALLOW_THREADS
|
||||||
|
if (dd->default_factory == NULL) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "None");
|
fprintf(fp, "None");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
PyObject_Print(dd->default_factory, fp, 0);
|
PyObject_Print(dd->default_factory, fp, 0);
|
||||||
}
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, ", ");
|
fprintf(fp, ", ");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
sts = PyDict_Type.tp_print((PyObject *)dd, fp, 0);
|
sts = PyDict_Type.tp_print((PyObject *)dd, fp, 0);
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, ")");
|
fprintf(fp, ")");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
static int
|
static int
|
||||||
bool_print(PyBoolObject *self, FILE *fp, int flags)
|
bool_print(PyBoolObject *self, FILE *fp, int flags)
|
||||||
{
|
{
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs(self->ob_ival == 0 ? "False" : "True", fp);
|
fputs(self->ob_ival == 0 ? "False" : "True", fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,9 @@ complex_print(PyComplexObject *v, FILE *fp, int flags)
|
||||||
char buf[100];
|
char buf[100];
|
||||||
complex_to_buf(buf, sizeof(buf), v,
|
complex_to_buf(buf, sizeof(buf), v,
|
||||||
(flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR);
|
(flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR);
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs(buf, fp);
|
fputs(buf, fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -867,11 +867,15 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
return status;
|
return status;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "{...}");
|
fprintf(fp, "{...}");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "{");
|
fprintf(fp, "{");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
any = 0;
|
any = 0;
|
||||||
for (i = 0; i <= mp->ma_mask; i++) {
|
for (i = 0; i <= mp->ma_mask; i++) {
|
||||||
dictentry *ep = mp->ma_table + 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
|
/* Prevent PyObject_Repr from deleting value during
|
||||||
key format */
|
key format */
|
||||||
Py_INCREF(pvalue);
|
Py_INCREF(pvalue);
|
||||||
if (any++ > 0)
|
if (any++ > 0) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, ", ");
|
fprintf(fp, ", ");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
if (PyObject_Print((PyObject *)ep->me_key, fp, 0)!=0) {
|
if (PyObject_Print((PyObject *)ep->me_key, fp, 0)!=0) {
|
||||||
Py_DECREF(pvalue);
|
Py_DECREF(pvalue);
|
||||||
Py_ReprLeave((PyObject*)mp);
|
Py_ReprLeave((PyObject*)mp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, ": ");
|
fprintf(fp, ": ");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
if (PyObject_Print(pvalue, fp, 0) != 0) {
|
if (PyObject_Print(pvalue, fp, 0) != 0) {
|
||||||
Py_DECREF(pvalue);
|
Py_DECREF(pvalue);
|
||||||
Py_ReprLeave((PyObject*)mp);
|
Py_ReprLeave((PyObject*)mp);
|
||||||
|
@ -896,7 +905,9 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
|
||||||
Py_DECREF(pvalue);
|
Py_DECREF(pvalue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "}");
|
fprintf(fp, "}");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
Py_ReprLeave((PyObject*)mp);
|
Py_ReprLeave((PyObject*)mp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2241,7 +2241,9 @@ PyFile_WriteString(const char *s, PyObject *f)
|
||||||
err_closed();
|
err_closed();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs(s, fp);
|
fputs(s, fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (!PyErr_Occurred()) {
|
else if (!PyErr_Occurred()) {
|
||||||
|
|
|
@ -334,7 +334,9 @@ float_print(PyFloatObject *v, FILE *fp, int flags)
|
||||||
char buf[100];
|
char buf[100];
|
||||||
format_float(buf, sizeof(buf), v,
|
format_float(buf, sizeof(buf), v,
|
||||||
(flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR);
|
(flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR);
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs(buf, fp);
|
fputs(buf, fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -425,7 +425,10 @@ static int
|
||||||
int_print(PyIntObject *v, FILE *fp, int flags)
|
int_print(PyIntObject *v, FILE *fp, int flags)
|
||||||
/* flags -- not used but required by interface */
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -282,19 +282,28 @@ list_print(PyListObject *op, FILE *fp, int flags)
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "[...]");
|
fprintf(fp, "[...]");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "[");
|
fprintf(fp, "[");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
for (i = 0; i < Py_Size(op); i++) {
|
for (i = 0; i < Py_Size(op); i++) {
|
||||||
if (i > 0)
|
if (i > 0) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, ", ");
|
fprintf(fp, ", ");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
if (PyObject_Print(op->ob_item[i], fp, 0) != 0) {
|
if (PyObject_Print(op->ob_item[i], fp, 0) != 0) {
|
||||||
Py_ReprLeave((PyObject *)op);
|
Py_ReprLeave((PyObject *)op);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "]");
|
fprintf(fp, "]");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
Py_ReprLeave((PyObject *)op);
|
Py_ReprLeave((PyObject *)op);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,14 +279,18 @@ internal_print(PyObject *op, FILE *fp, int flags, int nesting)
|
||||||
#endif
|
#endif
|
||||||
clearerr(fp); /* Clear any previous error condition */
|
clearerr(fp); /* Clear any previous error condition */
|
||||||
if (op == NULL) {
|
if (op == NULL) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "<nil>");
|
fprintf(fp, "<nil>");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (op->ob_refcnt <= 0)
|
if (op->ob_refcnt <= 0)
|
||||||
/* XXX(twouters) cast refcount to long until %zd is
|
/* XXX(twouters) cast refcount to long until %zd is
|
||||||
universally available */
|
universally available */
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "<refcnt %ld at %p>",
|
fprintf(fp, "<refcnt %ld at %p>",
|
||||||
(long)op->ob_refcnt, op);
|
(long)op->ob_refcnt, op);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
else if (Py_Type(op)->tp_print == NULL) {
|
else if (Py_Type(op)->tp_print == NULL) {
|
||||||
PyObject *s;
|
PyObject *s;
|
||||||
if (flags & Py_PRINT_RAW)
|
if (flags & Py_PRINT_RAW)
|
||||||
|
|
|
@ -577,20 +577,28 @@ set_tp_print(PySetObject *so, FILE *fp, int flags)
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
return status;
|
return status;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "%s(...)", so->ob_type->tp_name);
|
fprintf(fp, "%s(...)", so->ob_type->tp_name);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "%s([", so->ob_type->tp_name);
|
fprintf(fp, "%s([", so->ob_type->tp_name);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
while (set_next(so, &pos, &entry)) {
|
while (set_next(so, &pos, &entry)) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs(emit, fp);
|
fputs(emit, fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
emit = separator;
|
emit = separator;
|
||||||
if (PyObject_Print(entry->key, fp, 0) != 0) {
|
if (PyObject_Print(entry->key, fp, 0) != 0) {
|
||||||
Py_ReprLeave((PyObject*)so);
|
Py_ReprLeave((PyObject*)so);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputs("])", fp);
|
fputs("])", fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
Py_ReprLeave((PyObject*)so);
|
Py_ReprLeave((PyObject*)so);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -788,7 +788,7 @@ PyString_AsStringAndSize(register PyObject *obj,
|
||||||
static int
|
static int
|
||||||
string_print(PyStringObject *op, FILE *fp, int flags)
|
string_print(PyStringObject *op, FILE *fp, int flags)
|
||||||
{
|
{
|
||||||
Py_ssize_t i;
|
Py_ssize_t i, str_len;
|
||||||
char c;
|
char c;
|
||||||
int quote;
|
int quote;
|
||||||
|
|
||||||
|
@ -806,6 +806,7 @@ string_print(PyStringObject *op, FILE *fp, int flags)
|
||||||
if (flags & Py_PRINT_RAW) {
|
if (flags & Py_PRINT_RAW) {
|
||||||
char *data = op->ob_sval;
|
char *data = op->ob_sval;
|
||||||
Py_ssize_t size = Py_Size(op);
|
Py_ssize_t size = Py_Size(op);
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
while (size > INT_MAX) {
|
while (size > INT_MAX) {
|
||||||
/* Very long strings cannot be written atomically.
|
/* Very long strings cannot be written atomically.
|
||||||
* But don't write exactly INT_MAX bytes at a time
|
* But don't write exactly INT_MAX bytes at a time
|
||||||
|
@ -821,6 +822,7 @@ string_print(PyStringObject *op, FILE *fp, int flags)
|
||||||
#else
|
#else
|
||||||
fwrite(data, 1, (int)size, fp);
|
fwrite(data, 1, (int)size, fp);
|
||||||
#endif
|
#endif
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,8 +832,13 @@ string_print(PyStringObject *op, FILE *fp, int flags)
|
||||||
!memchr(op->ob_sval, '"', Py_Size(op)))
|
!memchr(op->ob_sval, '"', Py_Size(op)))
|
||||||
quote = '"';
|
quote = '"';
|
||||||
|
|
||||||
|
str_len = Py_Size(op);
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fputc(quote, fp);
|
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];
|
c = op->ob_sval[i];
|
||||||
if (c == quote || c == '\\')
|
if (c == quote || c == '\\')
|
||||||
fprintf(fp, "\\%c", c);
|
fprintf(fp, "\\%c", c);
|
||||||
|
@ -847,6 +854,7 @@ string_print(PyStringObject *op, FILE *fp, int flags)
|
||||||
fputc(c, fp);
|
fputc(c, fp);
|
||||||
}
|
}
|
||||||
fputc(quote, fp);
|
fputc(quote, fp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,16 +188,24 @@ static int
|
||||||
tupleprint(PyTupleObject *op, FILE *fp, int flags)
|
tupleprint(PyTupleObject *op, FILE *fp, int flags)
|
||||||
{
|
{
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, "(");
|
fprintf(fp, "(");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
for (i = 0; i < Py_Size(op); i++) {
|
for (i = 0; i < Py_Size(op); i++) {
|
||||||
if (i > 0)
|
if (i > 0) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fprintf(fp, ", ");
|
fprintf(fp, ", ");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
if (PyObject_Print(op->ob_item[i], fp, 0) != 0)
|
if (PyObject_Print(op->ob_item[i], fp, 0) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (Py_Size(op) == 1)
|
i = Py_Size(op);
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
if (i == 1)
|
||||||
fprintf(fp, ",");
|
fprintf(fp, ",");
|
||||||
fprintf(fp, ")");
|
fprintf(fp, ")");
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue