diff options
Diffstat (limited to 'pkg/syncevent/syncevent_example_test.go')
-rw-r--r-- | pkg/syncevent/syncevent_example_test.go | 108 |
1 files changed, 0 insertions, 108 deletions
diff --git a/pkg/syncevent/syncevent_example_test.go b/pkg/syncevent/syncevent_example_test.go deleted file mode 100644 index bfb18e2ea..000000000 --- a/pkg/syncevent/syncevent_example_test.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2020 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package syncevent - -import ( - "fmt" - "sync/atomic" - "time" -) - -func Example_ioReadinessInterrputible() { - const ( - evReady = Set(1 << iota) - evInterrupt - ) - errNotReady := fmt.Errorf("not ready for I/O") - - // State of some I/O object. - var ( - br Broadcaster - ready uint32 - ) - doIO := func() error { - if atomic.LoadUint32(&ready) == 0 { - return errNotReady - } - return nil - } - go func() { - // The I/O object eventually becomes ready for I/O. - time.Sleep(100 * time.Millisecond) - // When it does, it first ensures that future calls to isReady() return - // true, then broadcasts the readiness event to Receivers. - atomic.StoreUint32(&ready, 1) - br.Broadcast(evReady) - }() - - // Each user of the I/O object owns a Waiter. - var w Waiter - w.Init() - // The Waiter may be asynchronously interruptible, e.g. for signal - // handling in the sentry. - go func() { - time.Sleep(200 * time.Millisecond) - w.Receiver().Notify(evInterrupt) - }() - - // To use the I/O object: - // - // Optionally, if the I/O object is likely to be ready, attempt I/O first. - err := doIO() - if err == nil { - // Success, we're done. - return /* nil */ - } - if err != errNotReady { - // Failure, I/O failed for some reason other than readiness. - return /* err */ - } - // Subscribe for readiness events from the I/O object. - id := br.SubscribeEvents(w.Receiver(), evReady) - // When we are finished blocking, unsubscribe from readiness events and - // remove readiness events from the pending event set. - defer UnsubscribeAndAck(&br, w.Receiver(), evReady, id) - for { - // Attempt I/O again. This must be done after the call to SubscribeEvents, - // since the I/O object might have become ready between the previous call - // to doIO and the call to SubscribeEvents. - err = doIO() - if err == nil { - return /* nil */ - } - if err != errNotReady { - return /* err */ - } - // Block until either the I/O object indicates it is ready, or we are - // interrupted. - events := w.Wait() - if events&evInterrupt != 0 { - // In the specific case of sentry signal handling, signal delivery - // is handled by another system, so we aren't responsible for - // acknowledging evInterrupt. - return /* errInterrupted */ - } - // Note that, in a concurrent context, the I/O object might become - // ready and then not ready again. To handle this: - // - // - evReady must be acknowledged before calling doIO() again (rather - // than after), so that if the I/O object becomes ready *again* after - // the call to doIO(), the readiness event is not lost. - // - // - We must loop instead of just calling doIO() once after receiving - // evReady. - w.Ack(evReady) - } -} |