mirror of https://github.com/tinygo-org/tinygo.git
Nia Weiss
4 years ago
committed by
Ron Evans
3 changed files with 172 additions and 0 deletions
@ -0,0 +1,90 @@ |
|||
// +build !scheduler.none
|
|||
|
|||
package runtime |
|||
|
|||
import ( |
|||
"internal/task" |
|||
"sync/atomic" |
|||
"unsafe" |
|||
) |
|||
|
|||
// notifiedPlaceholder is a placeholder task which is used to indicate that the condition variable has been notified.
|
|||
var notifiedPlaceholder task.Task |
|||
|
|||
// Cond is a simplified condition variable, useful for notifying goroutines of interrupts.
|
|||
type Cond struct { |
|||
t *task.Task |
|||
} |
|||
|
|||
// Notify sends a notification.
|
|||
// If the condition variable already has a pending notification, this returns false.
|
|||
func (c *Cond) Notify() bool { |
|||
for { |
|||
t := (*task.Task)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&c.t)))) |
|||
switch t { |
|||
case nil: |
|||
// Nothing is waiting yet.
|
|||
// Apply the notification placeholder.
|
|||
if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.t)), unsafe.Pointer(t), unsafe.Pointer(¬ifiedPlaceholder)) { |
|||
return true |
|||
} |
|||
case ¬ifiedPlaceholder: |
|||
// The condition variable has already been notified.
|
|||
return false |
|||
default: |
|||
// Unblock the waiting task.
|
|||
if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.t)), unsafe.Pointer(t), nil) { |
|||
runqueuePushBack(t) |
|||
return true |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Poll checks for a notification.
|
|||
// If a notification is found, it is cleared and this returns true.
|
|||
func (c *Cond) Poll() bool { |
|||
for { |
|||
t := (*task.Task)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&c.t)))) |
|||
switch t { |
|||
case nil: |
|||
// No notifications are present.
|
|||
return false |
|||
case ¬ifiedPlaceholder: |
|||
// A notification arrived and there is no waiting goroutine.
|
|||
// Clear the notification and return.
|
|||
if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.t)), unsafe.Pointer(t), nil) { |
|||
return true |
|||
} |
|||
default: |
|||
// A task is blocked on the condition variable, which means it has not been notified.
|
|||
return false |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Wait for a notification.
|
|||
// If the condition variable was previously notified, this returns immediately.
|
|||
func (c *Cond) Wait() { |
|||
cur := task.Current() |
|||
for { |
|||
t := (*task.Task)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&c.t)))) |
|||
switch t { |
|||
case nil: |
|||
// Condition variable has not been notified.
|
|||
// Block the current task on the condition variable.
|
|||
if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.t)), nil, unsafe.Pointer(cur)) { |
|||
task.Pause() |
|||
return |
|||
} |
|||
case ¬ifiedPlaceholder: |
|||
// A notification arrived and there is no waiting goroutine.
|
|||
// Clear the notification and return.
|
|||
if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.t)), unsafe.Pointer(t), nil) { |
|||
return |
|||
} |
|||
default: |
|||
panic("interrupt.Cond: condition variable in use by another goroutine") |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
// +build scheduler.none
|
|||
|
|||
package runtime |
|||
|
|||
import "runtime/interrupt" |
|||
|
|||
// Cond is a simplified condition variable, useful for notifying goroutines of interrupts.
|
|||
type Cond struct { |
|||
notified bool |
|||
} |
|||
|
|||
// Notify sends a notification.
|
|||
// If the condition variable already has a pending notification, this returns false.
|
|||
func (c *Cond) Notify() bool { |
|||
i := interrupt.Disable() |
|||
prev := c.notified |
|||
c.notified = true |
|||
interrupt.Restore(i) |
|||
return !prev |
|||
} |
|||
|
|||
// Poll checks for a notification.
|
|||
// If a notification is found, it is cleared and this returns true.
|
|||
func (c *Cond) Poll() bool { |
|||
i := interrupt.Disable() |
|||
notified := c.notified |
|||
c.notified = false |
|||
interrupt.Restore(i) |
|||
return notified |
|||
} |
|||
|
|||
// Wait for a notification.
|
|||
// If the condition variable was previously notified, this returns immediately.
|
|||
func (c *Cond) Wait() { |
|||
for !c.Poll() { |
|||
waitForEvents() |
|||
} |
|||
} |
Loading…
Reference in new issue