Optimizing synchronization objects

Daniel Santos daniel.santos at pobox.com
Tue Sep 15 23:15:07 CDT 2015


On 09/15/2015 08:26 PM, Vincent Povirk wrote:
>> The part I'm not sure about yet is how we notify the first process that
>> their object is now shared. My most sane thought for doing this (I have
>> plenty of others :) is adding a more generic mechanism to tell the client "I
>> have a message for you", but both SIGUSR1 and 2 are both being used. The
>> handler for SIGUSR1 could be modified so that it first asks the server what
>> the message is, which may be a "suspend thread" or "migrate object to
>> server." So before proceeding, I would like to know your preference on how
>> this should be handled.
> FWIW, in our discussion on #winehackers, I was assuming you'd do the
> equivalent of InterlockedExchange in shared memory (between wineserver
> and the client) that contains the object state.

Well, Alexandre doesn't like that approach. I still think that it's 
doable to manage such a thing and still have the wineserver know when 
something isn't right and respond accordingly and I would still love to 
be able to convince Alexandre of that! :)

> The client would
> notice as soon as it tried to do anything with the object that the
> object was moved to the server, and the server would know the previous
> state from the result of InterlockedExchange. (This assumes every
> valid object state, including a state indicating that it's in the
> server, can fit in 64 bits.)

I think that the idea Alexandre proposed is that the object will not use 
shared memory, so the "moving to the server" scenario occurs when a 
complex WaitForMultipleObjects (i.e., with mixed object types) is 
requested or another process gains access to the object.

> I'm not sure it's a good idea for the wineserver to have to wait on
> code in a windows process (which, if the process is really hosed,
> might never respond) before it can reply to a DuplicateHandle request.

Well, the wineserver can't actually block, but somewhere we have to 
cause the calling thread of the second process to block until the object 
is migrated to the sever.  I think that there's 3 ways to do this.

 1. When the second process makes a call to get a handle to the
    (previously private) object, block the calling thread (delay the
    response) until the object is migrated to the server, or
 2. When the second process makes a call to get a handle to the
    (previously private) object, trigger a migration but don't block the
    calling thread (pending a completed migration) until it makes a call
    to actually *use* that object (ReleaseSemaphore, QuerySemaphore,
    server_select, etc.), or
 3. Don't do anything until the second process makes a call to actually
    use the object, then trigger the migration and wait for it to finish.

For simplicity, I was heading for the first option, but greater 
throughput could be obtained by the second option (if this is happening 
a lot) and a process will have a greater chance of getting to use an 
optimized (local) object with the 3rd option (not that I think it's a 
good option, just trying to be complete).

> The only time you'd need to signal the client is when a thread is
> waiting on the object being moved, so that the thread can restart the
> wait using the server.

Ah, another good reason to share memory between client & server! :) 
Also, it would enable wait multiple with mixed object types w/o forcing 
the object to be migrated to the server too.

> I don't know how you plan to wait on
> process-local objects, but perhaps you can perform the wait in such a
> way that the server can interrupt it easily, without disturbing the
> thread if it's doing anything else?
>
I don't have a complete design for this yet. I'm thinking that a custom 
synchronization mechanism using futexes would be appropriate (not that 
I've done that before or even used futexes) so we just notify a futex.  
Without the shared memory, I  was thinking of having the server send 
SIGUSR1 (or some such) to the client and that handler would send a 
request to the server to see what it wanted. The server would reply by 
telling it to migrate some object and then the client would manage this 
from the handler. So with just kill(), I don't think you get a choice 
over which thread responds to it, so the handler would just need to be 
aware if it was actually waiting on a futex when it was signaled and 
manage that appropriately. Again, I haven't really worked that part out 
just yet.

Using shared memory is certainly another option -- then we just have the 
server mark the object as needing migration and signal a futex. When a 
wait is completed on the client, it should just always read that value 
to know why it was signaled.




More information about the wine-devel mailing list