diff options
-rw-r--r-- | src/runtime/cond.go | 90 | ||||
-rw-r--r-- | src/runtime/cond_nosched.go | 38 | ||||
-rw-r--r-- | testdata/goroutines.go | 44 |
3 files changed, 0 insertions, 172 deletions
diff --git a/src/runtime/cond.go b/src/runtime/cond.go deleted file mode 100644 index b27ab08ab..000000000 --- a/src/runtime/cond.go +++ /dev/null @@ -1,90 +0,0 @@ -//go: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) { - scheduleTask(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") - } - } -} diff --git a/src/runtime/cond_nosched.go b/src/runtime/cond_nosched.go deleted file mode 100644 index ff57f4146..000000000 --- a/src/runtime/cond_nosched.go +++ /dev/null @@ -1,38 +0,0 @@ -//go: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() - } -} diff --git a/testdata/goroutines.go b/testdata/goroutines.go index 5ac3b7318..fe4347df9 100644 --- a/testdata/goroutines.go +++ b/testdata/goroutines.go @@ -1,7 +1,6 @@ package main import ( - "runtime" "sync" "time" ) @@ -83,8 +82,6 @@ func main() { testGoOnInterface(Foo(0)) - testCond() - testIssue1790() done := make(chan int) @@ -172,47 +169,6 @@ func testGoOnBuiltins() { } } -func testCond() { - var cond runtime.Cond - go func() { - // Wait for the caller to wait on the cond. - time.Sleep(time.Millisecond) - - // Notify the caller. - ok := cond.Notify() - if !ok { - panic("notification not sent") - } - - // This notification will be buffered inside the cond. - ok = cond.Notify() - if !ok { - panic("notification not queued") - } - - // This notification should fail, since there is already one buffered. - ok = cond.Notify() - if ok { - panic("notification double-sent") - } - }() - - // Verify that the cond has no pending notifications. - ok := cond.Poll() - if ok { - panic("unexpected early notification") - } - - // Wait for the goroutine spawned earlier to send a notification. - cond.Wait() - - // The goroutine should have also queued a notification in the cond. - ok = cond.Poll() - if !ok { - panic("missing queued notification") - } -} - var once sync.Once func testGoOnInterface(f Itf) { |