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