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