Merge "veyron/tools/naming/simulator: reworked to use new modules and to be more useful."
diff --git a/runtimes/google/lib/sync/semaphore.go b/runtimes/google/lib/sync/semaphore.go
index b6ea778..87588e3 100644
--- a/runtimes/google/lib/sync/semaphore.go
+++ b/runtimes/google/lib/sync/semaphore.go
@@ -27,15 +27,13 @@
// "select" operation to determine whether to perform a semaphore operation or
// abort because the semaphore is close or the operation was canceled.
//
-// NOTE: when the Semaphore is closed, the Dec operation is unblocked, returning
-// an error (ErrClosed) if the semaphore value is 0. However, if the semaphore
-// value is non-zero, Dec might perform the decrement and return without an
-// error. In fact, the behavior may be nondeterministic, after the semaphore is
-// closed, Dec may sometimes return ErrClosed, and sometimes it may complete
-// normally (but only if the semaphore value is non-zero).
-//
-// TODO(jyh): Decide whether the close semantics matters, and revise this
-// implementation if it does.
+// NOTE: when the Semaphore is closed, the Dec (or DecN) operations are
+// unblocked, returning an error (ErrClosed) if the semaphore value is 0 (or
+// less than the DecN value), respectively. However, even with the Semaphore
+// closed, if the semaphore value is non-zero (or sufficient to satisfy the DecN
+// value), Dec (or DecN) performs the decrement successfully and returns without
+// an error. Regardless of whether the Semaphore is closed or not, Inc/IncN
+// succeed in incrementing the semaphore value.
type Semaphore struct {
mu sync.Mutex
value uint // GUARDED_BY(mu)
diff --git a/runtimes/google/lib/sync/semaphore_test.go b/runtimes/google/lib/sync/semaphore_test.go
index 13379b7..7b71b4d 100644
--- a/runtimes/google/lib/sync/semaphore_test.go
+++ b/runtimes/google/lib/sync/semaphore_test.go
@@ -133,9 +133,12 @@
for i := 0; i < N; i++ {
go dec(i)
}
- s.IncN(N)
+ s.IncN(N + 1)
s.Close()
pending.Wait()
+ if got, want := s.DecN(2, nil), ErrClosed; got != want {
+ t.Errorf("Expected error %v, got %v instead", want, got)
+ }
}
func TestCancel(t *testing.T) {