Burkhard Carstens wrote:
Am Montag, 24. Juli 2006 19:22 schrieb Vinzent Höfler:
Burkhard Carstens wrote:
Am Montag, 24. Juli 2006 17:27 schrieb Vinzent Hoefler:
- the rtlEvent works even with timeout (with my patch posted on
mantis), but this one clears the signaled state, when wait is
called.
*oh* Before the wait? That's not good. This cries for race
conditions and subtle deadlock situations.
thread synchronization uses this and takes care of it by calling
RTLeventstartwait which locks the associated mutex.
As far as I just read code and comments, it does it for Windows to
get Unix behaviour, although I don't see the point here, because this
just forces the race condition the POSIX-Threads implementation
actually tries to circumvent with this associated mutex.
>
I don't think so.

Well, in that case either I am totally stupid (won't be news, anyway) or I must have different source code:

From "rtl/unix/cthreads.inc":

|procedure intRTLEventStartWait(AEvent: PRTLEvent);
|var p:pintrtlevent;
|
|begin
|  p:=pintrtlevent(aevent);
|  pthread_mutex_lock(@p^.mutex);
|end;
|
|procedure intRTLEventWaitFor(AEvent: PRTLEvent);
|var p:pintrtlevent;
|
|begin
|  p:=pintrtlevent(aevent);
|  pthread_cond_wait(@p^.condvar, @p^.mutex);
|  pthread_mutex_unlock(@p^.mutex);
|end;

Which is pretty much what you described and if pthread_cond_wait() works as described, there's no race condition here.

But now "rtl/win/systhrd.inc":

|procedure intRTLEventStartWait(AEvent: PRTLEvent);
|begin
|  { this is to get at least some common behaviour on unix and win32:
|    events before startwait are lost on unix, so reset the event on
|    win32 as well }
|  ResetEvent(THANDLE(AEvent));
|end;
|
|procedure intRTLEventWaitFor(AEvent: PRTLEvent);
|const
|  INFINITE=dword(-1);
|begin
|  WaitForSingleObject(THANDLE(AEvent), INFINITE);
|end;

I don't see any locking in intRTLEventStartWait(), but I see the signal being cleared in an unprotected way. So the signal can still get set between the calls to intRTLStartWait() and intRTLEventWaitFor() which makes the clearing quite useless.

In unix, the mutex is locked, which ensures, there is not setevent between startwait and actual call to wait, because the call to wait seems to reset the cond, then releases the mutex and starts waiting.

Yes, and now I seem to understand why. Unix only implements transient signals. So if there's noone waiting on the signal, it gets lost. Windows OTOH seems to implement persistent signals. That's all the difference.

> In windows, this doesn't matter (resetting the event on
startwait), because it preserves the signaled state of the event.

It preserves the signalled state? By resetting it? I don't think so.

AFAICS, it resets the signal before actually starting to wait for it. So it still can sneak in if the timing is right. That's what I'd call a race condition.

> The wait call just returns immediately, if the event is allready signaled.
To me, this is fine. As long as rtlevent is used with this in mind, it should give a consistent behaviour on windows and linux. (see classes.inc thread synchronization)

You mean code like:

|if timeout>0 then
|  begin
|    RtlEventStartWait(SynchronizeTimeoutEvent);
|    RtlEventWaitFor(SynchronizeTimeoutEvent,timeout);
|  end
|  else
|    RtlEventResetEvent(SynchronizeTimeoutEvent);

So where's the code that makes sure that the thread signalling the event is (only) resumed between the two calls?

I'm not even sure, if Unix actually clears the event. The man-pages
don't seem to indicate so.

It does, at least with the timedwait. I tested that extensively.

Yes, and now I think we both know why. I seem to repeat myself, but it might be important: The difference is all between implementing transient and persistent signals.


Vinzent.
_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply via email to