Локальное хранилище потока в режиме ядра?

Существует ли эквивалент 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 для достижения чего-то подобного.

  • Существует ли официальный API режима ядра для достижения того, что мне нужно?
  • Есть ли причины избегать того, что я собираюсь сделать? Я знаю, что потенциально может возникнуть проблема с повторным входом (т. е. какой-то код вызывает меня, я перезаписываю значение TLS, а затем в конечном итоге вызываю исходный код, который может полагаться на TLS). Но это невозможно в моем конкретном случае?
  • Есть ли менее грязные способы решить эту проблему?

Заранее спасибо.

П.С.Теоретически можно использовать SEH (в котором также хранится информация для каждого потока). То есть обернуть код верхнего уровня с помощью __try/__except, затем там, где нужна контекстная информация — вызвать исключение continuableс некоторым параметром, в __exceptзаполняет параметр контекстной информацией, а затем возобновляет выполнение. И это 100% валидный поток программы, без использования недокументированных возможностей. Но тем не менее мне это кажется уродливым хаком, не говоря уже о сложностях с производительностью.

9
задан Daniel Roethlisberger 21 March 2012 в 00:08
поделиться