
MacOS Yosemite (10.10.5). Я знаю, что это раздел Unix/Linux... но думаю, что этот вопрос, вероятно, больше подходит здесь, чем в стране MacOS.
Мой терминал начал зависать при запуске, прежде чем показать приглашение... и загрузка ЦП резко возросла в то же время. Я могу нажать CTRL-C и затем получить приглашение (вероятно, выход из какого-то зависшего/работающего .bashrc/.profile/etc).
Я быстро понял, что определенные строки в моем .bashrc вызывали зависание. Это что-то новое (т.е. я ничего не менял в моем .bashrc и все работало нормально), так что что-то изменилось в системе.
Похоже, что передача определенных более длинных строк приводит к зависанию/скачку загрузки ЦП.
Я могу воспроизвести это, протянув струну tr -d '\n'
и посмотрев, зависнет ли она.
macattack:~ $ openssl rand -base64 93 | tr -d '\n'
eDsz4JqFX/HAVjplNI6WDWwPRp9l9snp6UKp/pLn+GbBvJx0+ZMvSJFS/SuCwjMRRXVXfUvBdkaH1R0UgCr2UOf283MvHVTRusLFEVPcGCIz1t3sFMU/3foRzNWVmattp@macattack:~ $ openssl rand -base64 94 | tr -d '\n'
^C
mattp@macattack:~ $ openssl rand -base64 94 | tr -du '\n'
^C
Похоже, что 93 символа — это магическое число, после которого tr начинает зависать. openssl не зависает (т.е. если я уберу канал ко tr
всему, то все закроется). Однако моя исходная проблемная строка оказалась другой длины.
mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log;' | tr -d '\n'
^C-bash: echo: write error: Interrupted system call
mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | tr -d '\n'
mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | wc -c
128
mattp@macattack:~ $
Это, вероятно, проблема с трубой, а не с tr
проблемой. Я могу воспроизвести ту же проблему с помощью sed
(команда не имеет смысла... просто иллюстрирует зависание).
mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log;' | sed 's/\n/ /g'
^C-bash: echo: write error: Interrupted system call
mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | sed 's/\n/ /g'
echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log
mattp@macattack:~
У меня закончились идеи по устранению этой неполадки.
Зависающие команды отлично работают на случайном сервере Centos Linux. До недавнего времени команды отлично работали на Mac. Я никогда раньше не сталкивался с зависанием конвейера. Я думал, что, возможно, проблема в странных символах во входных данных... но случайная строка OpenSSL показывает обратное. Значения ulimits такие же, как на другом Mac, на котором НЕТ этой проблемы.
mattp@macattack:~ $ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 7168
pipe size (512 bytes, -p) 1
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 709
virtual memory (kbytes, -v) unlimited
При использовании dtruss
on, tr
похоже, происходит зависание при вызове read_nocancel.
Обновлять
Прогресс. Нашел комментарий о зависании и размерах буфера конвейера. Украл тестовый скрипт отсюда: Каков размер буфера трубы?
Запуск во время возникновения проблемы показывает буфер канала 128 байт. Перезагрузите (проблема временно исчезает), и буфер канала составляет 65536 байт. Смотрите вывод теста ниже.
Итак, теперь вопрос в том, почему/как «что-то» уменьшает размер буфера канала в системе.
С проблемой
$ /bin/bash -c 'for p in {0..18}; do pipe-buffer-test.sh $((2 ** $p)) 0.5; done'
write size: 1; bytes successfully before error: 128
write size: 2; bytes successfully before error: 128
write size: 4; bytes successfully before error: 128
write size: 8; bytes successfully before error: 128
write size: 16; bytes successfully before error: 128
write size: 32; bytes successfully before error: 128
write size: 64; bytes successfully before error: 128
write size: 128; bytes successfully before error: 128
write size: 256; bytes successfully before error: 0
write size: 512; bytes successfully before error: 0
write size: 1024; bytes successfully before error: 0
write size: 2048; bytes successfully before error: 0
write size: 4096; bytes successfully before error: 0
write size: 8192; bytes successfully before error: 0
write size: 16384; bytes successfully before error: 0
write size: 32768; bytes successfully before error: 0
write size: 65536; bytes successfully before error: 0
write size: 131072; bytes successfully before error: 0
write size: 262144; bytes successfully before error: 0
После перезагрузки (проблема временно исчезла)
$ /bin/bash -c 'for p in {0..18}; do pipe-buffer-test.sh $((2 ** $p)) 0.5; done'
write size: 1; bytes successfully before error: 65536
write size: 2; bytes successfully before error: 65536
write size: 4; bytes successfully before error: 65536
write size: 8; bytes successfully before error: 65536
write size: 16; bytes successfully before error: 65536
write size: 32; bytes successfully before error: 65536
write size: 64; bytes successfully before error: 65536
write size: 128; bytes successfully before error: 65536
write size: 256; bytes successfully before error: 65536
write size: 512; bytes successfully before error: 65536
write size: 1024; bytes successfully before error: 65536
write size: 2048; bytes successfully before error: 65536
write size: 4096; bytes successfully before error: 65536
write size: 8192; bytes successfully before error: 65536
write size: 16384; bytes successfully before error: 65536
write size: 32768; bytes successfully before error: 65536
write size: 65536; bytes successfully before error: 65536
write size: 131072; bytes successfully before error: 0
write size: 262144; bytes successfully before error: 0
решение1
На основе комментария @Barmar о протечке буферов ядра я взглянул на текущие не-ОС kexts. Я понял, что есть относительно новый из недавней установки BlockBlock (https://objective-see.com/products/blockblock.html).
Удалил BlockBlock, перезапустил и проблема не повторилась. Так что BlockBlock был виновником в этом случае, и я сообщил о проблеме автору.
Однако это не особенно удовлетворяет, поскольку я в основном применял подход «догадки и проверки», чтобы выяснить причину, и, честно говоря, я не совсем понимаю первопричину (с точки зрения ОС), а значит, я не буду знать, как устранять подобные неполадки в будущем.
Если кто-то с этим столкнется и сможет более подробно объяснить, что происходит, и предложить подход к устранению неполадок, это будет гораздо лучшим ответом, чем «удалить BlockBlock».