Почему GLib прерывается при повторяющихся журналах? - PullRequest
2 голосов
/ 01 сентября 2010

Большую часть времени моя программа GLib работает хорошо.Однако, когда журналы типа

** (процесс: pid ): Сообщение (рекурсивное): бла-бла-бла

, программа будетabort.

В руководстве по GLib сказано, что G_LOG_FLAG_RECURSION по умолчанию считается фатальным.

Но я просто не могу понять, что означает "рекурсивные сообщения"?Когда произойдет повторное сообщение?

Спасибо

Ответы [ 2 ]

3 голосов
/ 22 октября 2010

Обратите внимание, что рекурсивный вызов подпрограммы ведения журнала g_ * может также произойти, если вы регистрируете пользовательский обработчик (с помощью g_log_set_handler) и этот обработчик (или один из его вызываемых) пытается записать ошибку с помощью вызова g_ * рутина.

Также обратите внимание, что glib решил, что любая рекурсия также должна быть фатальной (даже если она не бесконечна глубиной всего в один уровень). Это, безусловно, имеет смысл для случая, описанного в ответе sarnold о рекурсии на внутренний сбой, но может быть неочевидным при попытке исправить проблему в случае повторяющегося пользовательского обработчика. Итак, glib обнаруживает рекурсию уже при первом рекурсивном вызове g_ *; он даже не проверяет, подключен ли ваш пользовательский обработчик. Следовательно, вы никогда не увидите рекурсивный вызов в вашем обработчике. Все это означает, что такие усилия, как тщательная отмена регистрации обработчика внутри тела обработчика (и тому подобное), бесполезны.

Вы должны быть абсолютно уверены, что ничто из стека вызовов из вашего пользовательского обработчика никогда не вызовет подпрограмму g_ * (что может быть сложно, если вы обрабатываете вызовы во внешнем коде и усложняет такие вещи, как попытка доставить сообщение журнала удаленный пункт назначения или что-то).

3 голосов
/ 01 сентября 2010

Просматривая файл glib / gmessages.c, я получаю очень сильное впечатление, что G_LOG_FLAG_RECURSION установлено, если g_logv() необходимо зарегистрировать саму ошибку.

Рассмотрим нехватку памяти; если попытка выделения памяти не удалась, программа попытается зарегистрировать ошибку выделения памяти и, возможно, завершится. Когда подпрограмма регистрации пытается выделить память для регистрации сообщения, она, вероятно, потерпит неудачу. Таким образом, подпрограммы ведения журнала отслеживают, насколько «глубокими» они были вызваны, и переключают стратегию выделения памяти (они выделяются в стеке, а не в куче), если это рекурсивный вызов ведения журнала.

Каждый раз, когда подпрограммы регистрации получают сообщение об ошибке и хотят регистрировать ошибку, происходит что-то действительно плохое, поэтому имеет смысл попытаться войти в систему с другим механизмом и затем выйти.

Так что вы, вероятно, просто видите отдаленный симптом настоящей проблемы. Вы можете использовать ltrace(1), чтобы попытаться определить проблему, или включить дампы ядра (ulimit -c unlimited) и попытаться найти цепочку вызовов, вызывающую сбой программы, с помощью команды bt gdb.

...