[Vm-dev] Why isn't signalSemaphoreWithIndex() thread-safe?

Joshua Gargus schwa at fastmail.us
Sun Sep 20 22:02:59 UTC 2009


Eliot Miranda wrote:
>  
>
> ------------------------------------------------------------------------
>
>
>
> On Sun, Sep 20, 2009 at 1:00 PM, Eliot Miranda
> <eliot.miranda at gmail.com <mailto:eliot.miranda at gmail.com>> wrote:
>
>     Hi Josh,
>
>     On Sun, Sep 20, 2009 at 12:43 PM, Joshua Gargus <schwa at fastmail.us
>     <mailto:schwa at fastmail.us>> wrote:
>
>
>         Hi,
>
>         I've always assumed that signalSemaphoreWithIndex() must be
>         thread-safe;
>         after all, it's the "official" mechanism for notifying the
>         image that an
>         asynchronous event has occurred.  However, a pang of paranoia
>         prompted
>         me to actually look at the code, and it seems clearly unsafe.
>          This is
>         bad, because I've been using it to signal events from separate
>         native
>         threads.
>
>         What should we do about this?  It seems to me that it should
>         be wrapped
>         in a critical section, using the appropriate platform-specific
>         synchronization primitives.
>
>      
>     There's no need for this heavyweight approach because the VM can
>     only respond to these signals synchronously.
>
>
> On second reading I think what I wrote below is exactly what you
> implied.  Sorry.

Nope, you're always giving me too much credit ;-)  I wasn't thinking
about any particular implementation of thread-safety, only raising the
issue that (in my understanding) we don't have it.

>
>  
>
>      Instead we can use three variables per index to implement an
>     exclusion-free solution, thusly:
>
>     typedef struct { int lock; // accessed via e.g. XCHG to protect
>     signalRequest
>                            int requests;
>                            int responses;
>                } ExternalSignalRequest;
>
>     ExternalSignalRequest *externalSignalRequests;
>     int checkExternalSignalRequests;
>
>     void
>     requestSignal(int i)
>     {
>            while (!lock(&externalSignalRequests[i].lock))
>                  usleep(1);
>
>            ++externalSignalRequests[i].requests;
>
>             unlock(&externalSignalRequests[i].lock);
>
>             checkExternalSignalRequests = 1;
>             forceInterruptCheck();  // set a flag to cause the VM to
>     check for interrupts; in the stack VM this is stackLimit :=
>     (usqInt)-1;
>     }
>                            
>
>     The VM responds in checkEvents:
>
>         if (checkExternalSignalRequests)
>             for (i = 0; i < numExternalSemaphores; i++)
>                 while (externalSignalRequests[i]. responses
>     != externalSignalRequests[i]. requests) {
>                     signalSemaphoreWithIndex(i);
>                     externalSignalRequests[i]. responses;
>                 }
>


Am I correct that ExternalSignalRequest.reponses is never reset to zero,
instead eventually wrapping around?  That worried me for a minute, but I
see that it doesn't matter.  Neeto.

Your solution looks good; it's certainly nicer than a heavyweight
critical section, especially since contention will be infrequent.

Cheers,
Josh




>
>
>         Thanks,
>         Josh
>
>
>



More information about the Vm-dev mailing list