Re-implemented PlatformEvents through the new API

This commit is contained in:
Maxim Kartashev
2025-02-19 18:08:23 +04:00
parent 34109563bd
commit 5631c4e4c3
2 changed files with 77 additions and 38 deletions

View File

@@ -5617,7 +5617,9 @@ int PlatformEvent::park(jlong Millis) {
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_ParkHandle != nullptr , "Invariant");
if (!UseModernSynchAPI) {
guarantee(_ParkHandle != nullptr , "Invariant");
}
guarantee(Millis > 0 , "Invariant");
// CONSIDER: defer assigning a CreateEvent() handle to the Event until
@@ -5649,25 +5651,37 @@ int PlatformEvent::park(jlong Millis) {
// adjust Millis accordingly if we encounter a spurious wakeup.
const int MAXTIMEOUT = 0x10000000;
DWORD rv = WAIT_TIMEOUT;
while (_Event < 0 && Millis > 0) {
DWORD prd = Millis; // set prd = MAX (Millis, MAXTIMEOUT)
if (Millis > MAXTIMEOUT) {
prd = MAXTIMEOUT;
if (UseModernSynchAPI) {
while ((v = Atomic::load_acquire(&_Event)) < 0) {
HighResolutionInterval *phri = nullptr;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval(Millis);
}
::WaitOnAddress(&_Event, &v, sizeof(_Event), Millis);
delete phri; // if it is null, harmless
}
HighResolutionInterval *phri = nullptr;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval(prd);
} else {
DWORD rv = WAIT_TIMEOUT;
while (_Event < 0 && Millis > 0) {
DWORD prd = Millis; // set prd = MAX (Millis, MAXTIMEOUT)
if (Millis > MAXTIMEOUT) {
prd = MAXTIMEOUT;
}
HighResolutionInterval *phri = nullptr;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval(prd);
}
rv = ::WaitForSingleObject(_ParkHandle, prd);
assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed with return value: %lu", rv);
if (rv == WAIT_TIMEOUT) {
Millis -= prd;
}
delete phri; // if it is null, harmless
}
rv = ::WaitForSingleObject(_ParkHandle, prd);
assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
assert(rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed with return value: %lu", rv);
if (rv == WAIT_TIMEOUT) {
Millis -= prd;
}
delete phri; // if it is null, harmless
v = _Event;
}
v = _Event;
_Event = 0;
// see comment at end of PlatformEvent::park() below:
OrderAccess::fence();
@@ -5683,7 +5697,9 @@ void PlatformEvent::park() {
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_ParkHandle != nullptr, "Invariant");
if (!UseModernSynchAPI) {
guarantee(_ParkHandle != nullptr, "Invariant");
}
// Invariant: Only the thread associated with the Event/PlatformEvent
// may call park().
// Consider: use atomic decrement instead of CAS-loop
@@ -5695,21 +5711,35 @@ void PlatformEvent::park() {
guarantee((v == 0) || (v == 1), "invariant");
if (v != 0) return;
// Do this the hard way by blocking ...
// TODO: consider a brief spin here, gated on the success of recent
// spin attempts by this thread.
while (_Event < 0) {
// The following code is only here to maintain the
// characteristics/performance from when an ObjectMonitor
// "responsible" thread used to issue timed parks.
HighResolutionInterval *phri = nullptr;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval((jlong)1);
if (UseModernSynchAPI) {
while ((v = Atomic::load_acquire(&_Event)) < 0) {
// The following code is only here to maintain the
// characteristics/performance from when an ObjectMonitor
// "responsible" thread used to issue timed parks.
HighResolutionInterval *phri = nullptr;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval((jlong)1);
}
::WaitOnAddress(&_Event, &v, sizeof(_Event), INFINITE);
delete phri; // if it is null, harmless
}
} else {
// Do this the hard way by blocking ...
// TODO: consider a brief spin here, gated on the success of recent
// spin attempts by this thread.
while (_Event < 0) {
// The following code is only here to maintain the
// characteristics/performance from when an ObjectMonitor
// "responsible" thread used to issue timed parks.
HighResolutionInterval *phri = nullptr;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval((jlong)1);
}
DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE);
delete phri; // if it is null, harmless
assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", rv);
}
DWORD rv = ::WaitForSingleObject(_ParkHandle, INFINITE);
delete phri; // if it is null, harmless
assert(rv != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError());
assert(rv == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", rv);
}
// Usually we'll find _Event == 0 at this point, but as
@@ -5721,7 +5751,9 @@ void PlatformEvent::park() {
}
void PlatformEvent::unpark() {
guarantee(_ParkHandle != nullptr, "Invariant");
if (!UseModernSynchAPI) {
guarantee(_ParkHandle != nullptr, "Invariant");
}
// Transitions for _Event:
// 0 => 1 : just return
@@ -5737,9 +5769,14 @@ void PlatformEvent::unpark() {
// from the first park() call after an unpark() call which will help
// shake out uses of park() and unpark() without condition variables.
if (Atomic::xchg(&_Event, 1) >= 0) return;
::SetEvent(_ParkHandle);
if (UseModernSynchAPI) {
if (Atomic::xchg(&_Event, 1) >= 0) return;
// Changed from -1 to 1; the target thread's WaitOnAddress() must return now
::WakeByAddressAll((PVOID) &_Event);
} else {
if (Atomic::xchg(&_Event, 1) >= 0) return;
::SetEvent(_ParkHandle);
}
}

View File

@@ -41,8 +41,10 @@ class PlatformEvent : public CHeapObj<mtSynchronizer> {
public:
PlatformEvent() {
_Event = 0 ;
_ParkHandle = CreateEvent (nullptr, false, false, nullptr) ;
guarantee (_ParkHandle != nullptr, "invariant") ;
if (!UseModernSynchAPI) {
_ParkHandle = CreateEvent (nullptr, false, false, nullptr) ;
guarantee (_ParkHandle != nullptr, "invariant") ;
}
}
// Exercise caution using reset() and fired() - they may require MEMBARs