Skip to content
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

bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to #2403

Merged
merged 4 commits into from Jun 26, 2017

Conversation

pitrou
Copy link
Member

@pitrou pitrou commented Jun 26, 2017

This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).

…o lock

This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).
Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current code doesn't compute correctly the timeout when pthread_cond_timedwait() is interrupted by a signal. We should recompute the timeout using a deadline.

Something like select.select():

if (tvp)
    deadline = _PyTime_GetMonotonicClock() + timeout;

do {
    ... use tvp
    if (errno != EINTR)
        break;

    /* select() was interrupted by a signal */
    if (PyErr_CheckSignals())
        goto finally;

    if (tvp) {
        timeout = deadline - _PyTime_GetMonotonicClock();
        if (timeout < 0) {
            n = 0;
            break;
        }
        _PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_CEILING);
        /* retry select() with the recomputed timeout */
    }
} while (1);

@pitrou
Copy link
Member Author

pitrou commented Jun 26, 2017

Probably, but that's unrelated to this PR (and much less severe, IMHO).

if (microseconds == 0) {
status = pthread_mutex_trylock( &thelock->mut );
if (status != EBUSY)
CHECK_STATUS_PTHREAD("pthread_mutex_trylock[1]");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how these locks work. Can you please explain in a comment what happens when we fail to lock the mutex? Is it safe to call pthread_mutex_unlock() anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right that we may want to fail early when taking the mutex fails.

@vstinner
Copy link
Member

Probably, but that's unrelated to this PR (and much less severe, IMHO).

Right :-)

@vstinner
Copy link
Member

Probably, but that's unrelated to this PR (and much less severe, IMHO).

I opened http://bugs.python.org/issue30768: PyThread_acquire_lock_timed() should recompute the timeout when interrupted by a signal.

@pitrou
Copy link
Member Author

pitrou commented Jun 26, 2017

@Haypo, are you ok with the latest changes?

@pitrou pitrou merged commit f84ac42 into python:master Jun 26, 2017
@pitrou pitrou deleted the mutex_trylock branch June 26, 2017 18:41
@pitrou pitrou added needs backport to 2.7 type-bug An unexpected behavior, bug, or error labels Jun 26, 2017
pitrou added a commit to pitrou/cpython that referenced this pull request Jun 26, 2017
… not to (pythonGH-2403)

* bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to lock

This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).

* Update 2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst

* Avoid core logic when taking the mutex failed
(cherry picked from commit f84ac42)
@bedevere-bot
Copy link

GH-2418 is a backport of this pull request to the 3.6 branch.

pitrou added a commit to pitrou/cpython that referenced this pull request Jun 26, 2017
… not to (pythonGH-2403)

* bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to lock

This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).

* Update 2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst

* Avoid core logic when taking the mutex failed.
(cherry picked from commit f84ac42)
@bedevere-bot
Copy link

GH-2419 is a backport of this pull request to the 3.5 branch.

pitrou added a commit to pitrou/cpython that referenced this pull request Jun 26, 2017
… not to (pythonGH-2403)

* bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to lock

This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).

* Update 2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst

* Avoid core logic when taking the mutex failed.
(cherry picked from commit f84ac42)
@bedevere-bot
Copy link

GH-2420 is a backport of this pull request to the 2.7 branch.

pitrou added a commit that referenced this pull request Jun 26, 2017
… not to (GH-2403) (#2418)

* bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to lock

This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).

* Update 2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst

* Avoid core logic when taking the mutex failed
(cherry picked from commit f84ac42)
pitrou added a commit that referenced this pull request Jun 26, 2017
… not to (GH-2403) (#2419)

* bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to lock

This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).

* Update 2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst

* Avoid core logic when taking the mutex failed.
(cherry picked from commit f84ac42)
pitrou added a commit that referenced this pull request Jun 26, 2017
… not to (GH-2403) (#2420)

* [2.7] bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to (GH-2403)

* bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to lock

This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).

* Update 2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst

* Avoid core logic when taking the mutex failed.
(cherry picked from commit f84ac42)

* Remove test undef
}
if (success == PY_LOCK_ACQUIRED) thelock->locked = 1;
status = pthread_mutex_unlock( &thelock->mut );
CHECK_STATUS_PTHREAD("pthread_mutex_unlock[1]");

if (error) success = PY_LOCK_FAILURE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code should be moved into the last if block. It seems like error is not used outside this if block.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, error is set by CHECK_STATUS_PTHREAD (yes, silly macro...).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ow, ignored my previous comment in that case :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants