@@ -141,6 +141,9 @@ trait GenConcurrent[F[_], E] extends GenSpawn[F, E] {
141141
142142 F .deferred[Option [E ]] flatMap { preempt =>
143143 F .ref[Set [Fiber [F , ? , ? ]]](Set ()) flatMap { supervision =>
144+ // has to be done in parallel to avoid head of line issues
145+ val cancelAllF = supervision.get.flatMap(_.toList.parTraverse_(_.cancel))
146+
144147 MiniSemaphore [F ](n) flatMap { sem =>
145148 val results = ta traverse { a =>
146149 preempt.tryGet flatMap {
@@ -154,10 +157,43 @@ trait GenConcurrent[F[_], E] extends GenSpawn[F, E] {
154157 F .deferred[Outcome [F , E , B ]] flatMap { result =>
155158 val action = poll(sem.acquire) >> f(a)
156159 .guaranteeCase { oc =>
157- result.complete(oc) *> oc.fold(
158- preempt.complete(None ).void,
159- e => preempt.complete(Some (e)).void,
160- _ => F .unit) *> sem.release
160+ val completion = oc match {
161+ case Outcome .Succeeded (_) =>
162+ preempt.tryGet flatMap {
163+ case Some (Some (e)) =>
164+ result.complete(Outcome .Errored (e))
165+
166+ case Some (None ) =>
167+ result.complete(Outcome .Canceled ())
168+
169+ case None =>
170+ result.complete(oc)
171+ }
172+
173+ case Outcome .Errored (e) =>
174+ preempt.complete(Some (e)) flatMap { won =>
175+ if (won)
176+ result.complete(oc) <* cancelAllF.start // avoid deadlock
177+ else
178+ preempt.get flatMap {
179+ case Some (e) => result.complete(Outcome .Errored (e))
180+ case None => result.complete(Outcome .Canceled ())
181+ }
182+ }
183+
184+ case Outcome .Canceled () =>
185+ preempt.complete(None ) flatMap { won =>
186+ if (won)
187+ result.complete(oc) <* cancelAllF.start // avoid deadlock
188+ else
189+ preempt.get flatMap {
190+ case Some (e) => result.complete(Outcome .Errored (e))
191+ case None => result.complete(Outcome .Canceled ())
192+ }
193+ }
194+ }
195+
196+ completion *> sem.release
161197 }
162198 .void
163199 .voidError
@@ -177,11 +213,7 @@ trait GenConcurrent[F[_], E] extends GenSpawn[F, E] {
177213 }
178214 }
179215
180- results.flatMap(_.sequence) guaranteeCase {
181- case Outcome .Succeeded (_) => F .unit
182- // has to be done in parallel to avoid head of line issues
183- case _ => supervision.get.flatMap(_.toList.parTraverse_(_.cancel))
184- }
216+ results.flatMap(_.sequence).onCancel(cancelAllF)
185217 }
186218 }
187219 }
0 commit comments