PKGBUILD/vendor/periph.io/x/periph/periph_parallel.go
2018-12-07 20:42:30 +01:00

102 lines
2.2 KiB
Go

// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// This file contains the parallelized driver loading logic. It is meant to be
// load the drivers as fast as possible by parallelising work.
// +build !tinygo
package periph
import (
"errors"
"strconv"
"sync"
)
func initImpl() (*State, error) {
state = &State{}
// At this point, byName is guaranteed to be immutable.
cD := make(chan Driver)
cS := make(chan DriverFailure)
cE := make(chan DriverFailure)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for d := range cD {
state.Loaded = insertDriver(state.Loaded, d)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for f := range cS {
state.Skipped = insertDriverFailure(state.Skipped, f)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for f := range cE {
state.Failed = insertDriverFailure(state.Failed, f)
}
}()
stages, err := explodeStages()
if err != nil {
return state, err
}
loaded := make(map[string]struct{}, len(byName))
for _, s := range stages {
s.loadParallel(loaded, cD, cS, cE)
}
close(cD)
close(cS)
close(cE)
wg.Wait()
return state, nil
}
// loadParallel loads all the drivers for this stage in parallel.
//
// Updates loaded in a safe way.
func (s *stage) loadParallel(loaded map[string]struct{}, cD chan<- Driver, cS, cE chan<- DriverFailure) {
success := make(chan string)
go func() {
defer close(success)
wg := sync.WaitGroup{}
loop:
for name, drv := range s.drvs {
// Intentionally do not look at After(), only Prerequisites().
for _, dep := range drv.Prerequisites() {
if _, ok := loaded[dep]; !ok {
cS <- DriverFailure{drv, errors.New("dependency not loaded: " + strconv.Quote(dep))}
continue loop
}
}
// Not skipped driver, attempt loading in a goroutine.
wg.Add(1)
go func(n string, d Driver) {
defer wg.Done()
if ok, err := d.Init(); ok {
if err == nil {
cD <- d
success <- n
return
}
cE <- DriverFailure{d, err}
} else {
cS <- DriverFailure{d, err}
}
}(name, drv)
}
wg.Wait()
}()
for s := range success {
loaded[s] = struct{}{}
}
}