是否有与Windows中的内核模式驱动程序等效的线程本地存储(TLS)(准确地说是Win32)?内核模式下的线程本地存储?
我尽量做到:
从我的驱动程序的调度程序可以调用许多其它功能中最终(有可能是深调用堆栈)。我想提供一些特定于正在处理的请求的上下文信息。也就是说,我有一些结构,指针应该在所有被调用的函数中可见,而不必将它作为参数显式传递给每个函数。
使用静态/全球是不是一个完美的选择(多线程,同步对象等)。
如果这是一个用户模式代码 - 在这种情况下一个显然会使用TLS。但是AFAIK没有像TlsGetValue
/TlsSetValue
这样的内核模式函数。这是有道理的 - 对于那些需要工作的函数,必须首先分配一个进程范围的TLS索引。 OTOH驱动程序代码可以在任意线程上调用,而不限于特定的进程。
不过其实我并不需要一个持续线程专有存储。我只需要一个特定于线程的存储器用于我的顶级函数调用。
我想我知道如何“落实”的TLS,但在一个hackish的方式。我将永远使用预定义的索引(比如index = 0),而不是分配TLS索引。在顶层函数中,我将保存存储的TLS值,并用所需的值覆盖它。完成后,保存的值将被恢复。
幸运的是,我知道TLS是如何在Win32中实现。每个线程有一个TIB
结构(线程信息块)。在每个线程中,可以使用FS:[18h]
选择器访问它。 TIB
包含(除其他之外)由TLS使用的数组。其余的很简单。
但是我宁愿使用一个官方的API来实现类似的东西。
- 是否有官方的内核模式API来实现我所需要的?
- 是否有理由避免我打算做的事情?我知道有可能潜在地与重入的问题(即一些代码调用我,我覆盖TLS值,然后最终调用原始代码,它可以依靠TLS)。但是在我的具体情况下这是不可能的?
- 有没有较少的肮脏的方法来解决这个问题?
在此先感谢。
P.S.理论上可以使用SEH(也存储每线程信息)。也就是说,将顶级代码换成__try/__except
,然后在需要上下文信息的地方 - 用继续例外的某些参数,在__except
块中用参数填充上下文信息,然后恢复执行。这是一个100%有效的程序流程,不使用未记录的功能。但无论如何这似乎是一个丑陋的黑客攻击对我来说,更何况性能并发症。
优秀的答案,非常精确。我同意依靠特定的无证功能并不是一个好的做法。然而,我发现它非常难以想象TIB布局或访问方式可能会改变。此外,司机有不太严格的便携性要求恕我直言。使用全局数组并通过'KeGetCurrentProcessorNumber'访问它是一个非常好的主意。在我的特殊情况下,请求可能会到达IRQL的不确定位置,我不确定是否允许我提出这个请求(我称之为其他例程),但是绝对值得查看。 – valdo 2012-03-21 07:49:14
P.S.一张“链表”表格正是我想摆脱的一件事。非常感谢。 – valdo 2012-03-21 07:49:53
为什么你很难想象TIB的结构会发生变化? Win64必须改变了吗? ARM的情况可能会有所不同。即使这些字段保持不变,内核也不会重复使用它们来替代别的东西,并且会丢失数据(或者更糟糕的是,您可能会吹走它的数据)。 – Stewart 2012-03-21 15:38:20