Определение стека потока, который стоит на мьютексе
От: Рома Мик Россия http://romamik.com
Дата: 03.12.21 08:46
Оценка: -1
Изначально задача была определять ситуации, когда приложения "зависает" и сохранять стектрейс зависшего потока.
Для этого был заведен отдельный поток, который следит за основным потоком приложения: основной поток должен регулярно обновлять переменную, а наблюдающий поток раз в секунду проверяет, как давно она обновлялась, если прошло больше критического времени — надо сохранять стектрейс.
Получение стектрейса сделано с помощью "unwind.h" и работает хорошо.
Единственная сложность — код надо вызывать в том потоке, для которого нужен стектрейс. Для этого регистрируем обработчик сигнала SIGUSR2, и в нем сохраняем стектрейс. Т.е. наблюдающий поток отправляет сигнал, основной поток его получает, сохраняет стектрейс и сигналом же уведомляет наблюдающий поток, что он закончил. Это тоже работает хорошо.

Но если основной поток "повис" на мьютексе, то стектрейс состоит из всего двух записей:
000: 0x9c1ac /apex/com.android.runtime/lib/bionic/libc.so __epoll_pwait
001: 0x6df9c /apex/com.android.runtime/lib/bionic/libc.so epoll_wait


Дело происходит на андроиде. Но сильно подозреваю, что на любом линуксе, да и не только на нём, будет также.

Можно ли как-то узнать стек самого блокирующего вызова?
Re: Определение стека потока, который стоит на мьютексе
От: reversecode google
Дата: 03.12.21 09:03
Оценка: +1
для определения стека потока стоящем на мютексе — дедлоки
есть gdb
а то чем вы занимаетесь, называется некультурным словом
Re[2]: Определение стека потока, который стоит на мьютексе
От: Рома Мик Россия http://romamik.com
Дата: 03.12.21 09:10
Оценка:
Здравствуйте, reversecode, Вы писали:

R>для определения стека потока стоящем на мютексе — дедлоки

R>есть gdb
R>а то чем вы занимаетесь, называется некультурным словом
Это если это у тебя на машине происходит. А если у пользователя, которого ты не знаешь, и узнать толком не можешь?
Стек при краше тоже можно в дебаггере посмотреть, но почему-то сбор и отправка крашдампов на проде существуют (в той же винде, когда приложение падает, предлагают аж в сам микрософт крашдамп отправить). С такими зависаниями чем ситуация отличается?
Отредактировано 03.12.2021 9:13 Рома Мик . Предыдущая версия .
Re[3]: Определение стека потока, который стоит на мьютексе
От: reversecode google
Дата: 03.12.21 09:17
Оценка: -3
меняйте проф, у вас явно гуманитарное образование, в ит с этим тяжело
Re: Определение стека потока, который стоит на мьютексе
От: lpd Черногория  
Дата: 03.12.21 09:18
Оценка: 3 (1)
Здравствуйте, Рома Мик, Вы писали:


РМ>Но если основной поток "повис" на мьютексе, то стектрейс состоит из всего двух записей:

РМ>
РМ>000: 0x9c1ac /apex/com.android.runtime/lib/bionic/libc.so __epoll_pwait
РМ>001: 0x6df9c /apex/com.android.runtime/lib/bionic/libc.so epoll_wait
РМ>


Похоже не на мьютекс, а на epoll сокетов, очевидно.

РМ>Можно ли как-то узнать стек самого блокирующего вызова?


Возможно, какая-то из библиотек или программа собраны без отладочной информации, или без stack-frame pointers.

Вообще, печать стеков может systemtap. Это печатать стеков при всех вызовах функции, но небольшым скриптом можно учесть изменение переменной по таймауту.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Отредактировано 03.12.2021 9:22 lpd . Предыдущая версия .
Re[2]: Определение стека потока, который стоит на мьютексе
От: reversecode google
Дата: 03.12.21 09:21
Оценка:
даю подсказку, если мютекс и висит то в другом потоке
Re[3]: Определение стека потока, который стоит на мьютексе
От: lpd Черногория  
Дата: 03.12.21 09:26
Оценка:
Здравствуйте, reversecode, Вы писали:

R>даю подсказку, если мютекс и висит то в другом потоке


Тогда послать сигнал потоку.
Или просто получить дамп всего приложения сигналом, либо так.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re[3]: Определение стека потока, который стоит на мьютексе
От: Рома Мик Россия http://romamik.com
Дата: 03.12.21 10:05
Оценка:
Здравствуйте, reversecode, Вы писали:

R>даю подсказку, если мютекс и висит то в другом потоке

Меня не интересует, что там делает другой поток, который занял мьютекс. Моя задача найти место в коде, которое в основном потоке ждёт чего-то, что может произойти не "мгновенно", и переделать на асинхронный код. Это не дедлок, просто какие-то длительные операции.
Re[2]: Определение стека потока, который стоит на мьютексе
От: Рома Мик Россия http://romamik.com
Дата: 03.12.21 10:47
Оценка:
Здравствуйте, lpd, Вы писали:

lpd>Здравствуйте, Рома Мик, Вы писали:



РМ>>Но если основной поток "повис" на мьютексе, то стектрейс состоит из всего двух записей:

РМ>>
РМ>>000: 0x9c1ac /apex/com.android.runtime/lib/bionic/libc.so __epoll_pwait
РМ>>001: 0x6df9c /apex/com.android.runtime/lib/bionic/libc.so epoll_wait
РМ>>


lpd>Похоже не на мьютекс, а на epoll сокетов, очевидно.

Да, взял один стек, а ситуацию другую. С мьютексами тоже стек из двух строчек, но другой.
000: 0x5e4ac /apex/com.android.runtime/lib/bionic/libc.so syscall
001: 0x636ac /apex/com.android.runtime/lib/bionic/libc.so


РМ>>Можно ли как-то узнать стек самого блокирующего вызова?

lpd>Возможно, какая-то из библиотек или программа собраны без отладочной информации, или без stack-frame pointers.
Отдадочная информация в рантайме не используется, собираются только адреса. Отладочную информацию применяю уже потом отдельной утилитой.
Я в этом совсем профан и возможно скажу глупость: как вообще могут функции работать без stack-frame pointers? Процессор же должен куда-то перейти по return? В каком-то виде эта информация обязана быть. Вот её и надо извлечь.

lpd>Вообще, печать стеков может systemtap. Это печатать стеков при всех вызовах функции, но небольшым скриптом можно учесть изменение переменной по таймауту.

Интересно, но судя по написанному работает только x86, а у меня ARM.
Ну и это, видимо, только на своей машине можно делать, а не на проде у всех пользователей. На своей машине у меня дебаггер есть, вот только ситуация не воспроизводится.
Re[3]: Определение стека потока, который стоит на мьютексе
От: lpd Черногория  
Дата: 03.12.21 11:16
Оценка: 3 (1)
Здравствуйте, Рома Мик, Вы писали:

РМ>Отдадочная информация в рантайме не используется, собираются только адреса. Отладочную информацию применяю уже потом отдельной утилитой.

Думаю можно собрать бинарники с отладочной информацией, и лучше включить frame-pointers. Но с arm/android я почти не работал.

РМ>Я в этом совсем профан и возможно скажу глупость: как вообще могут функции работать без stack-frame pointers? Процессор же должен куда-то перейти по return? В каком-то виде эта информация обязана быть. Вот её и надо извлечь.


Адрес возрата на стеке в любом случае есть. Без frame-pointerов нет адресов текущего фрейма (в rbp на x86_64), и на стек не сохраняется адрес предыдущего по call-stack фрейма(push $rbp;mov $rsp, $rbp), поэтому где именно этот адрес возврата неизвестно. Для отладки используют отладочную информацию, например в форматах DWARF или ORC — из нее можно для любой точки кода функции получить позиции на стеке адреса возрата и локальных переменных.

Либо как вариант печатать весь стек, и среди всех адресов будут попадаться адреса возврата.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Отредактировано 03.12.2021 11:19 lpd . Предыдущая версия . Еще …
Отредактировано 03.12.2021 11:18 lpd . Предыдущая версия .
Re[4]: Определение стека потока, который стоит на мьютексе
От: Рома Мик Россия http://romamik.com
Дата: 03.12.21 11:46
Оценка:
Здравствуйте, lpd, Вы писали:

РМ>>Отдадочная информация в рантайме не используется, собираются только адреса. Отладочную информацию применяю уже потом отдельной утилитой.

lpd>Думаю можно собрать бинарники с отладочной информацией, и лучше включить frame-pointers. Но с arm/android я почти не работал.
У меня локально вообще отладочный билд. В нем всё включено, но стеки такие собираются. Подозреваю, что делается системный вызов, а система собрана без всего этого.

РМ>>Я в этом совсем профан и возможно скажу глупость: как вообще могут функции работать без stack-frame pointers? Процессор же должен куда-то перейти по return? В каком-то виде эта информация обязана быть. Вот её и надо извлечь.

lpd>Адрес возрата на стеке в любом случае есть. Без frame-pointerов нет адресов текущего фрейма (в rbp на x86_64), и на стек не сохраняется адрес предыдущего по call-stack фрейма(push $rbp;mov $rsp, $rbp), поэтому где именно этот адрес возврата неизвестно. Для отладки используют отладочную информацию, например в форматах DWARF или ORC — из нее можно для любой точки кода функции получить позиции на стеке адреса возрата и локальных переменных.
Понятно, спасибо. Интересно.

lpd>Либо как вариант печатать весь стек, и среди всех адресов будут попадаться адреса возврата.

Вариант куда копать, спасибо. Можно как-нибудь, перебирая адреса, понять, что адрес похож на адрес внутри нашего исполняемого кода? Чтобы отфильтровать только такие значения.
Re[5]: Определение стека потока, который стоит на мьютексе
От: lpd Черногория  
Дата: 03.12.21 11:53
Оценка: 3 (1)
Здравствуйте, Рома Мик, Вы писали:

lpd>>Либо как вариант печатать весь стек, и среди всех адресов будут попадаться адреса возврата.

РМ>Вариант куда копать, спасибо. Можно как-нибудь, перебирая адреса, понять, что адрес похож на адрес внутри нашего исполняемого кода? Чтобы отфильтровать только такие значения.

Адреса кода будут из сегментов .text. Адреса всех областей памяти сегментов программы и библиотек проще всего для процесса получить из /proc/$PID/maps. У сегментов кода там флаг eXecutable.
На стеке среди значений локальных переменных, кроме адресов текущего call-stackа, будут попадаться неперезатертые адреса возврата от старых call-stackов. Так что в каждом случае придется вручную разбираться какие из адресов нужны.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Отредактировано 03.12.2021 12:04 lpd . Предыдущая версия . Еще …
Отредактировано 03.12.2021 11:54 lpd . Предыдущая версия .
Re[3]: Определение стека потока, который стоит на мьютексе
От: ononim  
Дата: 04.12.21 09:18
Оценка:
R>>а то чем вы занимаетесь, называется некультурным словом
РМ>Это если это у тебя на машине происходит. А если у пользователя, которого ты не знаешь, и узнать толком не можешь?
у пользователя делаете coredump присылаете его разработчику и открываете в gdb
разумеется требуется наличие символов для ехе который у пользователя работает
Как много веселых ребят, и все делают велосипед...
Re[4]: Определение стека потока, который стоит на мьютексе
От: Рома Мик Россия http://romamik.com
Дата: 04.12.21 10:01
Оценка:
Здравствуйте, ononim, Вы писали:

R>>>а то чем вы занимаетесь, называется некультурным словом

РМ>>Это если это у тебя на машине происходит. А если у пользователя, которого ты не знаешь, и узнать толком не можешь?
O>у пользователя делаете coredump присылаете его разработчику и открываете в gdb
O>разумеется требуется наличие символов для ехе который у пользователя работает
Я кстати посмотрел, lldb тоже стек не видит в этой ситуации, если просто на брейкпойнте встать.
Re[5]: Определение стека потока, который стоит на мьютексе
От: lpd Черногория  
Дата: 04.12.21 10:04
Оценка: +1
Здравствуйте, Рома Мик, Вы писали:

РМ>Я кстати посмотрел, lldb тоже стек не видит в этой ситуации, если просто на брейкпойнте встать.


Попробовать загрузить в отладчик символьную информацию для libc, версии установленной у пользователя.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.