Обнаружение тупиков на мьютексах в многопоточных приложениях
5
получать информацию о захвате и освобождении мьютексов. Для пе-
рехвата вызова системной функции futex() необходимо изменить код
ядра. В нем изменяются файлы futex.c и futex.h. В файл futex.h добав-
ляется объявление — указатель на функцию и объявление самой
функции, устанавливающей ловушку:
typedef long (*futex_hook_t)(u32 __user *uaddr, int op,
u32 val);
futex_hook_t set_futex_hook(futex_hook_t hook);
В файл futex.c добавляется описание функции-ловушки:
static futex_hook_t futex_hook;
futex_hook_t set_futex_hook(futex_hook_t hook) {
futex_hook_t old_hook = futex_hook;
futex_hook = hook;
printk(KERN_INFO "futex hook %p\n", hook);
return old_hook;
}
EXPORT_SYMBOL_GPL(set_futex_hook);
Данная функция сохраняет в переменную futex_hook адрес функ-
ции, переданной в качестве аргумента, и возвращает предыдущее
значение данной переменной.
В функцию ядра futex() также необходимо внести изменения —
добавить вызов нашей функции-ловушки. Вызов функции-ловушки
(futex- hook) записывается в конец функции futex() до вызова функ-
ции do_futex() следующим образом:
if (futex_hook) futex_hook(uaddr, op, val);
Описанный механизм позволяет устанавливать в качестве функ-
ции-ловушки любую функцию, определенную в пространстве ядра (в
том числе — в загружаемом модуле ядра), прототип которой соот-
ветствует заданному:
long (*futex_hook_t)(u32 __user *uaddr, int op, u32 val);
Внедренная в код ядра функция позволит получить следующую
информацию об освобождении/блокировке потоков на мьютексах:
•
текущее действие («+» — поток заблокирован на данном
мьютексе, «–» — мьютекс освобожден и блокированный поток мо-
жет продолжить свое выполнение);
•
идентификатор текущего потока, который будет заблокиро-
ван/разбужен;
•
идентификатор потока, захватившего мьютекс, на котором бу-
дет заблокирован текущий поток;
•
адрес мьютекса в пространстве пользователя;