Quantcast
Channel: Recent Gists from luqmana
Viewing all articles
Browse latest Browse all 41

parker.rs

$
0
0
parker.rs
pubstructParker{
state:AtomicI8,
event_handle:AtomicU32,// The bottom 2 bits of HANDLE are always 0 if you really wanted to get fancy and stuff state there
// https://devblogs.microsoft.com/oldnewthing/20050121-00/?p=36633
}
implParker{
pubfnnew() -> Self{
Self{
state:AtomicI8::new(EMPTY),
event_handle:AtomicU32::new(c::INVALID_HANDLE_VALUEasu32),
}
}
// Assumes this is only called by the thread that owns the Parker,
// which means that `self.state != PARKED`.
pubunsafefnpark(&self){
// Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
// first case.
ifself.state.fetch_sub(1,Acquire) == NOTIFIED{
return;
}
if c::WaitOnAddress::is_available(){
loop{
// Wait for something to happen, assuming it's still set to PARKED.
c::WaitOnAddress(self.ptr(),&PARKEDas*const_as c::LPVOID,1, c::INFINITE);
// Change NOTIFIED=>EMPTY but leave PARKED alone.
ifself.state.compare_and_swap(NOTIFIED,EMPTY,Acquire) == NOTIFIED{
// Actually woken up by unpark().
return;
}else{
// Spurious wake up. We loop to try again.
}
}
}else{
// Wait for unpark() to produce this event.
c::WaitForSingleObject(self.event_handle(), c::INFINITE);
// Set the state back to EMPTY (from either PARKED or NOTIFIED).
// Note that we don't just write EMPTY, but use swap() to also
// include an acquire-ordered read to synchronize with unpark()'s
// release-ordered write.
self.state.swap(EMPTY,Acquire);
}
}
// Assumes this is only called by the thread that owns the Parker,
// which means that `self.state != PARKED`.
pubunsafefnpark_timeout(&self,timeout:Duration){
// Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
// first case.
ifself.state.fetch_sub(1,Acquire) == NOTIFIED{
return;
}
if c::WaitOnAddress::is_available(){
// Wait for something to happen, assuming it's still set to PARKED.
c::WaitOnAddress(
self.ptr(),
&PARKEDas*const_as c::LPVOID,
1,
dur2timeout(timeout),
);
// Set the state back to EMPTY (from either PARKED or NOTIFIED).
// Note that we don't just write EMPTY, but use swap() to also
// include an acquire-ordered read to synchronize with unpark()'s
// release-ordered write.
ifself.state.swap(EMPTY,Acquire) == NOTIFIED{
// Actually woken up by unpark().
}else{
// Timeout or spurious wake up.
// We return either way, because we can't easily tell if it was the
// timeout or not.
}
}else{
// Wait for unpark() to produce this event.
let unparked = c::WaitForSingleObject(self.event_handle(),dur2timeout(timeout))
== c::WAIT_OBJECT_0;
// Set the state back to EMPTY (from either PARKED or NOTIFIED).
let prev_state = self.state.swap(EMPTY,Acquire);
if !unparked && prev_state == NOTIFIED{
// Timed out (or error)
}
}
}
pubfnunpark(&self){
// Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
// wake the thread in the first case.
//
// Note that even NOTIFIED=>NOTIFIED results in a write. This is on
// purpose, to make sure every unpark() has a release-acquire ordering
// with park().
ifself.state.swap(NOTIFIED,Release) == PARKED{
if c::WakeByAddressSingle::is_available(){
unsafe{
c::WakeByAddressSingle(self.ptr());
}
}else{
unsafe{
c::SetEvent(self.event_handle());
}
}
}
}
fnptr(&self) -> c::LPVOID{
&self.stateas*const_as c::LPVOID
}
fnevent_handle(&self) -> c::HANDLE{
constINVALID:u32 = !0;// c::INVALID_HANDLE_VALUE
matchself.event_handle.load(Relaxed){
INVALID => {
let handle = unsafe{
c::CreateEventW(
ptr::null_mut(),
0,// Auto-reset event object
0,// Initially nonsignaled
ptr::null(),
)
};
if handle.is_null(){
panic!("Unable to create event handle: error {}", unsafe{
c::GetLastError()
});
}
matchself
.event_handle
.compare_exchange(INVALID, handle asu32,Relaxed,Relaxed)
{
Ok(_) => handle,
Err(h) => {
// Lost the race to another thread initializing HANDLE before we did.
// Closing our handle and using theirs instead.
unsafe{
c::CloseHandle(handle);
}
h as c::HANDLE
}
}
}
handle => handle as c::HANDLE,
}
}
}

Viewing all articles
Browse latest Browse all 41

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>