-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
[2.7] bpo-32186: Release the GIL during fstat and lseek calls #4651
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@vstinner can you review? |
In fileio, there were 3 fstat() calls and one lseek() call that did not release the GIL during the call. This can cause all threads to hang for unlimited time when using io.FileIO with inaccessible NFS server.
I prefer to wait until PR #4652 is merged before reviewing the backport to Python 2.7. |
|
||
Py_BEGIN_ALLOW_THREADS | ||
res = fstat(self->fd, &st); | ||
Py_END_ALLOW_THREADS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi,
wouldn't it be slightly better to make the 2 sys calls in the same ALLOW_THREADS block, given they follow each other in the usual case ?
like this:
Py_BEGIN_ALLOW_THREADS
res = fstat(self->fd, &st);
if (res == 0) {
pos = lseek(self->fd, 0L, SEEK_CUR);
}
Py_END_ALLOW_THREADS
if (res == 0) {
end = st.st_size;
# etc..
regards,
gst.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review @gst. The code is less clear this way, and we are not calling this in a tight loop, so I don't think this optimization is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed.
but now I see that the lseek call isn't checked for error (return value == -1)..
shouldn't it be actually ?
EDIT: well, it falls back to the returned default value in such case, so guess it's good enough..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the current error handling is fragile. But I want to make the minimal change needed for this issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The best would be to backport _Py_fstat() from master: it returns the file size properly on Windows by using GetFileInformationByHandle(). Be honestly, I don't think that it's worth it and it's perfectly fine to release/acquire the GIL twice in this short function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The builtin "file" type has the same bug (doesn't release the GIL) but isn't fixed by this change.
Please update also file_read() in Objects/fileobject.c.
|
||
Py_BEGIN_ALLOW_THREADS | ||
res = fstat(self->fd, &st); | ||
Py_END_ALLOW_THREADS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The best would be to backport _Py_fstat() from master: it returns the file size properly on Windows by using GetFileInformationByHandle(). Be honestly, I don't think that it's worth it and it's perfectly fine to release/acquire the GIL twice in this short function.
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
I checked Modules/_io/fileio.c: with your PR, it seems like the GIL is now released for all "blocking" syscalls. |
@vstinner in 2.7 file_read() in Objects/fileobject.c:
What do you suggest to change? |
In Python 2.7, dircheck() calls fstat() and new_buffersize() calls fstat() and lseek() without releasing the GIL. I was talking about these functions. |
@vstinner, you requested changes in the patch in Objects/fileobj.c - but the code looks correct to me. Can you explain what is the issue and how do you think it should be fixed? |
Python 2.7, see my " <~~~~ GIL not released":
|
@vstinner thanks! what a horrible code duplication :-) I'll add a minimal fix in the next commit. |
Thanks. |
Same issue seen in fileio exists also in fileobject, fixed in the same way.
I have made the requested changes; please review again |
Thanks for making the requested changes! @vstinner: please review the changes made to this pull request. |
Thank you @nirs for the update, the PR is now complete ;-) I merged it. |
In fileio, there were 3 fstat() calls and one lseek() call that did not
release the GIL during the call. This can cause all threads to hang for
unlimited time when using io.FileIO with inaccessible NFS server.
https://bugs.python.org/issue32186