Существует ли эквивалентный локальному потоку хранилище (TLS) для драйверов режима ядра в Windows (точнее, Win32)?
Чего я пытаюсь достичь:
В конечном счете, в рамках процедуры отправки моего драйвера он может вызывать многие другие функции (может быть глубокий стек вызовов). Я хочу предоставить некоторую контекстную информацию, относящуюся к обрабатываемому запросу. То есть у меня есть некоторая структура, указатель на которую должен быть виден во всех вызываемых функциях, без явной передачи ее в качестве параметра каждой функции.
Использование static / global не является идеальным вариантом (многопоточность, синхронизация объектов и т. Д.).
Если бы это был код пользовательского режима - очевидно, в такой ситуации можно было бы использовать TLS. Но в AFAIK нет функций режима ядра, таких как TlsGetValue
/ TlsSetValue
. И это имеет смысл - чтобы эти функции работали, нужно сначала выделить индекс TLS для всего процесса. Код драйвера OTOH может быть вызван в произвольном потоке, не ограничиваясь конкретным процессом.
Однако на самом деле мне не нужно постоянное хранилище, ориентированное на потоки. Мне просто нужно специфичное для потока хранилище для вызова функций верхнего уровня.
Я думаю, что знаю, как "реализовать" TLS, хотя и хакерским способом. Вместо выделения индекса TLS я всегда буду использовать предопределенный индекс (скажем, index = 0). В функции верхнего уровня я сохраню сохраненное значение TLS и перезапишу его нужным значением. По завершении сохраненное значение будет восстановлено.
К счастью, я знаю, как TLS реализован в Win32. Для каждого потока есть структура TIB
(блок информации о потоке). В каждом потоке к нему можно получить доступ с помощью селектора FS:[18h]
. TIB
содержит (среди прочего) массив, используемый TLS. Все остальное довольно просто.
Однако я бы предпочел использовать официальный API для достижения чего-то похожего.
- Существует ли официальный API режима ядра для достижения того, что мне нужно?
- Есть ли причины избегать того, что я планирую делать? Я знаю, что потенциально может быть проблема с повторным входом (то есть, некоторый код вызывает меня, я перезаписываю значение TLS и затем в конечном счете вызываю исходный код, который может полагаться на TLS). Но это не возможно в моем конкретном случае?
- Есть ли менее грязные способы решить эту проблему?
Заранее спасибо.
P.S. Теоретически можно использовать SEH (в котором также хранится информация для каждого потока). То есть, оберните код верхнего уровня на __try/__except
, затем там, где необходима контекстная информация - вызовите исключение продолжение с некоторым параметром, в блоке __except
заполните параметр контекстной информацией, и затем возобновите выполнение. И это 100% действительный программный поток, без использования недокументированных функций. Но, тем не менее, это кажется мне отвратительным занятием, не говоря уже о проблемах с производительностью.