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

termios.tcdrain hangs on MacOS #97001

Open
benthorner opened this issue Sep 21, 2022 · 0 comments
Open

termios.tcdrain hangs on MacOS #97001

benthorner opened this issue Sep 21, 2022 · 0 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@benthorner
Copy link

benthorner commented Sep 21, 2022

Bug report

The following Python program hangs forever on MacOS, but does not hang on Linux:

import os, termios, time
device_fd, tty_fd  = os.openpty()

def loop():
    while True:
        data = os.read(device_fd, 1)
        print(data)  # <--- never gets here
        time.sleep(.1)

from threading import Thread
thread = Thread(target=loop, daemon=True)
thread.start()

os.write(tty_fd, b'123')
termios.tcdrain(tty_fd)  # <--- gets stuck here
time.sleep(3)  # allow thread to read all data

Reading the data in a thread should mean there's absolutely no reason for tcdrain to hang. The docs say it only waits for the data to be "transmitted", which sounds different to "read". And there's the fact this works on Linux.

Any single-threaded call to tcdrain() using tty_fd also hangs, even if the os.write line is removed i.e. there's nothing for tcdrain to wait for write. When I try with a real file descriptor or a pipe I get an error: 'Inappropriate ioctl for device' - it's unclear if it's the combination of tcdrain and openpty or just tcdrain that's causing the issue.

When I sample the process using the MacOS Activity Monitor I get the following at the bottom of the call graph for the main thread (unchanging) and the secondary "read" thread (bottommost lines vary per sample) respectively:

...
+ 2553 termios_tcdrain  (in termios.cpython-39-darwin.so) + 56  [0x1048dedcc]
+   2553 tcdrain  (in libsystem_c.dylib) + 48  [0x19f27c454]
+     2553 ioctl  (in libsystem_kernel.dylib) + 36  [0x19f30b0c0]
+       2553 __ioctl  (in libsystem_kernel.dylib) + 8  [0x19f30b0d4]
...
  853 os_read  (in python3.9) + 320  [0x100d45ad8]
    853 _Py_read  (in python3.9) + 92  [0x100d35ca0]
      853 PyEval_RestoreThread  (in python3.9) + 24  [0x100cd2c7c]
        853 take_gil  (in python3.9) + 176  [0x100cd2550]
          852 _pthread_cond_wait  (in libsystem_pthread.dylib) + 1236  [0x19f34483c]
            ! 852 __psynch_cvwait  (in libsystem_kernel.dylib) + 8  [0x19f30a270]
              1 _pthread_cond_wait  (in libsystem_pthread.dylib) + 344  [0x19f3444c0]
                1 __gettimeofday  (in libsystem_kernel.dylib) + 12  [0x19f30aa0c]

The questions I'm struggling to answer:

  • What is the expected behaviour of tcdrain in this scenario?
  • If the Linux behaviour is expected, why does it not work on MacOS?

Your environment

  • CPython versions tested on: 3.9.13
  • Operating system and architecture: MacOS 12.5.1 (ARM CPU).

I've also tested on MacOS with an Intel CPU and another developer has tested on Linux (to prove it terminates there). Originally I thought the issue might be an OS issue and posted in the Apple dev forum about it.

@benthorner benthorner added the type-bug An unexpected behavior, bug, or error label Sep 21, 2022
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

No branches or pull requests

1 participant