GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — PyThread_acquire_lock_timed() should recompute the timeout when interrupted by a signal · Issue #74953 · python/cpython

PyThread_acquire_lock_timed() should recompute the timeout when interrupted by a signal #74953

New issue
Copy link
New issue
Copy link
Closed
Closed
PyThread_acquire_lock_timed() should recompute the timeout when interrupted by a signal#74953
Copy link
Labels
3.7 (EOL)end of lifeend of life

Description

@vstinner
vstinner
opened on Jun 26, 2017
Issue body actions
BPO 30768
Nosy @pitrou, @vstinner
PRs
  • bpo-30768: Recompute timeout on interrupted lock #4103
  • Files
  • interrupted_lock.py
  • test.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2017-06-26.13:50:01.691>
    labels = ['3.7']
    title = 'PyThread_acquire_lock_timed() should recompute the timeout when interrupted by a signal'
    updated_at = <Date 2017-10-25.00:15:14.862>
    user = 'https://github.com/vstinner'

    bugs.python.org fields:

    activity = <Date 2017-10-25.00:15:14.862>
    actor = 'vstinner'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = []
    creation = <Date 2017-06-26.13:50:01.691>
    creator = 'vstinner'
    dependencies = []
    files = ['47233', '47234']
    hgrepos = []
    issue_num = 30768
    keywords = ['patch']
    message_count = 10.0
    messages = ['296896', '296898', '296899', '304892', '304893', '304895', '304896', '304951', '304952', '304953']
    nosy_count = 3.0
    nosy_names = ['pitrou', 'vstinner', 'neologix']
    pr_nums = ['4103']
    priority = 'normal'
    resolution = None
    stage = 'resolved'
    status = 'open'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue30768'
    versions = ['Python 3.7']

    Activity

    1. vstinner commented on Jun 26, 2017

      @vstinner
      vstinner
      on Jun 26, 2017
      MemberAuthor
      More actions

      The current code of PyThread_acquire_lock_timed() (the implementation not using semaphore) 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);
    2. vstinner
      added
      3.7 (EOL)end of lifeend of life
      on Jun 26, 2017
    3. vstinner commented on Jun 26, 2017

      @vstinner
      vstinner
      on Jun 26, 2017
      MemberAuthor
      More actions

      See also the old bpo-12822: "NewGIL should use CLOCK_MONOTONIC if possible.".

    4. vstinner commented on Jun 26, 2017

      @vstinner
      vstinner
      on Jun 26, 2017
      MemberAuthor
      More actions

      See also the PEP-475 "Retry system calls failing with EINTR" and PEP-418 (time.monotonic).

    5. vstinner commented on Oct 24, 2017

      @vstinner
      vstinner
      on Oct 24, 2017
      MemberAuthor
      More actions

      interrupted_lock.py: test threading.Lock.acquire(timeout=1.0) with SIGALRM sent every 1 ms (so up to 1000 times in total). Example:

      haypo@selma$ ./python interrupted_lock.py
      acquire(timeout=1.0) took 1.0 seconds and got 1000 signals

      Oh, in fact, threading.Lock.acquire(timeout=1.0) already recomputes the timeout when interrupted.

      In Python stdlib, PyThread_acquire_lock_timed() is only called from one place with intr_flag=0: faulthandler watchdog thread, but this thread blocks all signals:

      /* we don't want to receive any signal */
      sigfillset(&set);
      pthread_sigmask(SIG_SETMASK, &set, NULL);
      
    6. vstinner commented on Oct 24, 2017

      @vstinner
      vstinner
      on Oct 24, 2017
      MemberAuthor
      More actions

      Ah, I found another caller of PyThread_acquire_lock_timed() with a timeout > 0 and intr_flag=0: _enter_buffered_busy() of Modules/_io/bufferedio.c:

          /* When finalizing, we don't want a deadlock to happen with daemon
           * threads abruptly shut down while they owned the lock.
           * Therefore, only wait for a grace period (1 s.).
           * Note that non-daemon threads have already exited here, so this
           * shouldn't affect carefully written threaded I/O code.
           */
          st = PyThread_acquire_lock_timed(self->lock, (PY_TIMEOUT_T)1e6, 0);
      
    7. vstinner commented on Oct 24, 2017

      @vstinner
      vstinner
      on Oct 24, 2017
      MemberAuthor
      More actions

      I wrote PR 4103 to fix the pthread+semaphore implementation of PyThread_acquire_lock_timed().

      Apply PR 4103, apply attached test.patch, recompile Python, and run interrupted_lock.py to test the PR. Result:

      haypo@selma$ ./python interrupted_lock.py
      acquire(timeout=1.0) took 1.0 seconds and got 911 signals

    8. vstinner commented on Oct 24, 2017

      @vstinner
      vstinner
      on Oct 24, 2017
      MemberAuthor
      More actions

      To check if you are using pthread+semaphore, use:

      haypo@selma$ ./python -c 'import sys; print(sys.thread_info)'
      sys.thread_info(name='pthread', lock='semaphore', version='NPTL 2.25')

      Here you have pthread+semaphore. It's Fedora 26 running Linux kernel 4.13.

    9. vstinner commented on Oct 24, 2017

      @vstinner
      vstinner
      on Oct 24, 2017
      MemberAuthor
      More actions

      New changeset 850a18e by Victor Stinner in branch 'master':
      bpo-30768: Recompute timeout on interrupted lock (GH-4103)
      850a18e

    10. vstinner commented on Oct 25, 2017

      @vstinner
      vstinner
      on Oct 25, 2017
      MemberAuthor
      More actions

      I merged my PR. Thanks Antoine Pitrou for the review!

      This change only impacts the io.BufferedWriter and io.BufferedReader during Python finalization. It has no effect on theading.Lock.acquire(). It might impact faulthandler.dump_traceback_later(), but in practice, it shouldn't change anything since the internal faulthandler watchdog thread blocks all signals.

      If I understand correctly, if the system clock is stepped back by 1 hour during Python finalization, after PyThread_acquire_lock_timed() computed the deadline, but before sem_timedwait() completed, _enter_buffered_busy() can be blocked during 1 hour.

      Moving the system clock backward by 1 hour occurs once a year on the DST change. But the race condition is unlikely since the size of the time window is only 1 second. The DST change should occur at Python shutdown when an io.BufferedReader or io.BufferedWriter is used.

      Since the race condition seems very unlikely and was never reported by another user, I propose to not backward this change. Moreover, I'm not confident to modify locks in a stable release :-)

    11. vstinner
      closed this as completedon Oct 25, 2017
    12. vstinner commented on Oct 25, 2017

      @vstinner
      vstinner
      on Oct 25, 2017
      MemberAuthor
      More actions

      Oh, the pthread condvar+mutex implementation still has the bug, so I reopen the issue.

    13. vstinner
      reopened this on Oct 25, 2017
    14. ezio-melotti
      transferred this issue fromon Apr 10, 2022
    15. vstinner
      added 2 commits that reference this issue on Jun 17, 2022

      gh-74953: Add _PyTime_FromMicrosecondsClamp() function (#93942)

      e444752

      gh-74953: Fix PyThread_acquire_lock_timed() code recomputing the time…

      f64557f
    16. miss-islington
      added 2 commits that reference this issue on Jun 17, 2022

      pythongh-74953: Fix PyThread_acquire_lock_timed() code recomputing th…

      6d03bba

      gh-74953: Fix PyThread_acquire_lock_timed() code recomputing the time…

      1353b8a
    17. vstinner
      added a commit that references this issue on Jun 19, 2022

      gh-74953: Reformat PyThread_acquire_lock_timed() (#93947)

      2664d9a
    18. vstinner commented on Jun 21, 2022

      @vstinner
      vstinner
      on Jun 21, 2022
      MemberAuthor
      More actions

      I looked again to this issue. IMO it's now fully fixed, see my comment for the rationale: #93946 (comment)

    19. vstinner
      closed this as completedon Jun 21, 2022
    20. vstinner
      added a commit that references this issue on Jun 21, 2022

      gh-74953: _PyThread_cond_after() uses _PyTime_t (#94056)

      c7a79bb
    21. serhiy-storchaka
      added a commit that references this issue on Jun 26, 2022

      Revert 30935 defer bpo45162 to 312 (#94285)

      1ffde3e
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.7 (EOL)end of lifeend of life

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions

        You are visitor 01402503 — GeezerVison does not store the pages you look up.
        Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.