@@ -55,7 +55,11 @@ func catchPanics(routineDone chan<- error) {
55
55
56
56
// Go implements Nursery.
57
57
func (n * nursery ) Go (routine func () error ) {
58
- n .routinesCount .Add (1 )
58
+ new := n .routinesCount .Add (1 )
59
+ if new < 2 {
60
+ panic ("use of nursery after end of block" )
61
+ }
62
+
59
63
if n .limiter == nil {
60
64
select {
61
65
case n .goRoutine <- routine :
@@ -69,9 +73,6 @@ func (n *nursery) Go(routine func() error) {
69
73
case n .limiter <- struct {}{}:
70
74
// We are below our limit.
71
75
n .goNew (routine )
72
- case <- n .Done ():
73
- // Context canceled.
74
- n .routinesCount .Add (- 1 )
75
76
case n .goRoutine <- routine :
76
77
// Successfully reused a goroutine.
77
78
}
@@ -82,6 +83,8 @@ func (n *nursery) goNew(routine Routine) {
82
83
go func () {
83
84
defer catchPanics (n .errors )
84
85
for r := range n .goRoutine {
86
+ // TODO: add option to skip routine if context is canceled.
87
+
85
88
err := r ()
86
89
if err != nil {
87
90
n .onError (err )
@@ -90,13 +93,8 @@ func (n *nursery) goNew(routine Routine) {
90
93
}
91
94
}()
92
95
93
- select {
94
- case <- n .Done ():
95
- // Context canceled.
96
- n .routinesCount .Add (- 1 )
97
- case n .goRoutine <- routine :
98
- // routine forwarded.
99
- }
96
+ // Execute routine.
97
+ n .goRoutine <- routine
100
98
}
101
99
102
100
// Block starts a nursery block that returns when all goroutines have returned.
@@ -106,6 +104,9 @@ func (n *nursery) goNew(routine Routine) {
106
104
// goroutines to handle context cancellation. Error returned by block closure
107
105
// always trigger a context cancellation and is returned if it occurs before a
108
106
// default goroutine error handler is called.
107
+ // Calling [Nursery].Go() after end of block always panic. Calling [Nursery].Go
108
+ // after context is canceled still runs the provided function, you're responsible
109
+ // for handling cancellation.
109
110
func Block (block func (n Nursery ) error , opts ... BlockOption ) (err error ) {
110
111
n := newNursery ()
111
112
for _ , opt := range opts {
@@ -130,6 +131,7 @@ func Block(block func(n Nursery) error, opts ...BlockOption) (err error) {
130
131
}
131
132
132
133
// Start block.
134
+ n .routinesCount .Add (1 ) // Bypass end of block check.
133
135
n .Go (func () error {
134
136
e := block (n )
135
137
if e != nil {
@@ -138,6 +140,7 @@ func Block(block func(n Nursery) error, opts ...BlockOption) (err error) {
138
140
err = e
139
141
})
140
142
}
143
+ n .routinesCount .Add (- 1 ) // Restore end of block check.
141
144
return nil
142
145
})
143
146
0 commit comments