User handles changes

Jacek Caban jacek at codeweavers.com
Mon Feb 7 11:47:04 CST 2022


Hi all,


I've been recently looking at user handle handling in win32u and how it 
should be split from user32 (and PE world in general). In general, 
having something similar to how we handle gdi handles now would be nice. 
We're able to expose DC_ATTR struct (and possibly others in the future), 
allowing simple functions like an attribute getter, to avoid any 
syscalls, while keeping internal 'kernel' part private to win32u.


Unlike gdi handles, user handles need to be really interprocess, which 
makes things more tricky. Having it working only for current process 
would not buy us much, because we'd need to expose the fallback part 
from win32u anyway. I also considered avoiding the problem and simply 
expose additional Wine-specific functions from win32u. That could work, 
but such differences in handles capabilities from Windows quickly add up 
and the number of cases where it would affect design decisions convinced 
me to just try to make shared memory work. We were talking about 
extending shared memory usage for wineserver communication anyway.


I created a branch with my prototype of implementation:

https://github.com/jacekcw/wine/tree/user-handles

I think that this is enough to get a sense of how I think it could work. 
Those patches still need some work and testing, but it's close enough.


It implements user handle table using shared memory that is writeable 
from server, but read-only for clients. Using shared memory for the 
handles table alone is enough to reimplement things like IsWindow() and 
GetWindowThreadProcessId(). Handle table entry contains three objects:

- server object, not much changes here

- client 'kernel' object. Using windows as an example, this is WND 
struct. We will want to make it private to win32u (instead of user32), 
but other than that its mechanism can stay mostly unchanged, except we 
will need to more careful to match server state closely

- shared struct representing current state of the object. This replaces 
some fields of above types, but will also be accessible from PE code.


user-handles branch reimplements GetWindowLong* on top of shared memory 
(mostly, it's not complete there, but remaining cases will be similar 
once complete). This also seems to match how it works on Windows: win32u 
exposes NtUserSetWindowLong, but no Get* equivalent. The getter can be 
lock-free because the only race it needs to worry about is if the handle 
was closed and memory reused (in which case we'd read a garbage). To 
avoid that, we simply need to recheck the handle after reading the 
memory. Also note that guarantees of user_section lock still hold. 
Although this memory is modified on server side, it's always initiated 
by a server call call from proper thread when SetWindowLong* holds the lock.


There are some similarities to Huw's and Rémi's shared memory patches 
that are used in Proton, but this patchset touches different areas. 
user-handles branch also doesn't need locking mechanisms because thread 
safety is guaranteed by other means. We may need something like serial 
number-based synchronization when we will need a way to read multiple 
fields who's integrity cannot be guaranteed differently, but that 
doesn't seem necessary for cases that I needed so far. Anyway, I believe 
that those patches can be adopted to use mechanisms from my series, but 
the overlap is small at this point.


Any feedback is appreciated.


Thanks,

Jacek




More information about the wine-devel mailing list