impl-mutex.go
func (p *process) doClose() {
	// this function is only be called once (protected by p.Lock()).
	// and it will panic (on closing channels) otherwise.

	close(p.closing) // signal that we're shutting down (Closing)

	for len(p.children) > 0 || len(p.waitfors) > 0 {
		for plc, _ := range p.children {
			child := plc.Child()
			if child != nil { // check because child may already have been removed.
				go child.Close() // force all children to shut down
			}
			plc.ParentClear()
		}
		p.children = nil // clear them. release memory.

		// we must be careful not to iterate over waitfors directly, as it may
		// change under our feet.
		wf := p.waitfors
		p.waitfors = nil // clear them. release memory.
		for w, _ := range wf {
			// Here, we wait UNLOCKED, so that waitfors who are in the middle of
			// adding a child to us can finish. we will immediately close the child.
			p.Unlock()
			<-w.ChildClosed() // wait till all waitfors are fully closed (before teardown)
			p.Lock()
			w.ParentClear()
		}
	}

	if p.teardown != nil {
		p.closeErr = p.teardown() // actually run the close logic (ok safe to teardown)
	}
	close(p.closed) // signal that we're shut down (Closed)

	// go remove all the parents from the process links. optimization.
	go func(waiters []*processLink) {
		for _, pl := range waiters {
			pl.ClearChild()
			pr, ok := pl.Parent().(*process)
			if !ok {
				// parent has already been called to close
				continue
			}
			pr.Lock()
			delete(pr.waitfors, pl)
			delete(pr.children, pl)
			pr.Unlock()
		}
	}(p.waiters) // pass in so
	p.waiters = nil // clear them. release memory.
}
func (p *process) doClose() {
	// this function is only be called once (protected by p.Lock()).
	// and it will panic (on closing channels) otherwise.

	close(p.closing) // signal that we're shutting down (Closing)

	for len(p.children) > 0 || len(p.waitfors) > 0 {
		for plc, _ := range p.children {
			child := plc.Child()
			if child != nil { // check because child may already have been removed.
				go child.Close() // force all children to shut down
			}
			plc.ParentClear()
		}
		p.children = nil // clear them. release memory.

		// we must be careful not to iterate over waitfors directly, as it may
		// change under our feet.
		wf := p.waitfors
		p.waitfors = nil // clear them. release memory.
		for w, _ := range wf {
			// Here, we wait UNLOCKED, so that waitfors who are in the middle of
			// adding a child to us can finish. we will immediately close the child.
			p.Unlock()
			<-w.ChildClosed() // wait till all waitfors are fully closed (before teardown)
			p.Lock()
			w.ParentClear()
		}
	}

	if p.teardown != nil {
		p.closeErr = p.teardown() // actually run the close logic (ok safe to teardown)
	}
	close(p.closed) // signal that we're shut down (Closed)

	// go remove all the parents from the process links. optimization.
	go func(waiters []*processLink) {
		for _, pl := range waiters {
			pl.ClearChild()
			pr, ok := pl.Parent().(*process)
			if !ok {
				// parent has already been called to close
				continue
			}
			pr.Lock()
			delete(pr.waitfors, pl)
			delete(pr.children, pl)
			pr.Unlock()
		}
	}(p.waiters) // pass in so
	p.waiters = nil // clear them. release memory.
}
func ( p * process ) doClose ( ) { // this function is only be called once (protected by p.Lock()). // and it will panic (on closing channels) otherwise. close ( p . closing ) // signal that we're shutting down (Closing) for len ( p . children ) > 0 || len ( p . waitfors ) > 0 { for plc , _ := range p . children { child := plc . Child ( ) if child != nil { // check because child may already have been removed. go child . Close ( ) // force all children to shut down } plc . ParentClear ( ) } p . children = nil // clear them. release memory. // we must be careful not to iterate over waitfors directly, as it may // change under our feet. wf := p . waitfors p . waitfors = nil // clear them. release memory. for w , _ := range wf { // Here, we wait UNLOCKED, so that waitfors who are in the middle of // adding a child to us can finish. we will immediately close the child. p . Unlock ( ) <- w . ChildClosed ( ) // wait till all waitfors are fully closed (before teardown) p . Lock ( ) w . ParentClear ( ) } } if p . teardown != nil { p . closeErr = p . teardown ( ) // actually run the close logic (ok safe to teardown) } close ( p . closed ) // signal that we're shut down (Closed) // go remove all the parents from the process links. optimization. go func ( waiters [ ] * processLink ) { for _ , pl := range waiters { pl . ClearChild ( ) pr , ok := pl . Parent ( ) . ( * process ) if ! ok { // parent has already been called to close continue } pr . Lock ( ) delete ( pr . waitfors , pl ) delete ( pr . children , pl ) pr . Unlock ( ) } } ( p . waiters ) // pass in so p . waiters = nil // clear them. release memory. }
// the _actual_ close process.
the _actual_ close process .