func (c *cgroup) Processes(subsystem Name, recursive bool) ([]Process, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err != nil {
		return nil, c.err
	}
	return c.processes(subsystem, recursive)
}
Processes returns the processes running inside the cgroup along
with the subsystem used, pid, and path
package cgroups
import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	v1 "github.com/containerd/cgroups/stats/v1"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
)
func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources, opts ...InitOpts) (Cgroup, error) {
	config := newInitConfig()
	for _, o := range opts {
		if err := o(config); err != nil {
			return nil, err
		}
	}
	subsystems, err := hierarchy()
	if err != nil {
		return nil, err
	}
	var active []Subsystem
	for _, s := range subsystems {
		if err := initializeSubsystem(s, path, resources); err != nil {
			if err == ErrControllerNotActive {
				if config.InitCheck != nil {
					if skerr := config.InitCheck(s, path, err); skerr != nil {
						if skerr != ErrIgnoreSubsystem {
							return nil, skerr
						}
					}
				}
				continue
			}
			return nil, err
		}
		active = append(active, s)
	}
	return &cgroup{
		path:       path,
		subsystems: active,
	}, nil
}
func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
	config := newInitConfig()
	for _, o := range opts {
		if err := o(config); err != nil {
			return nil, err
		}
	}
	var activeSubsystems []Subsystem
	subsystems, err := hierarchy()
	if err != nil {
		return nil, err
	}
	for _, s := range pathers(subsystems) {
		p, err := path(s.Name())
		if err != nil {
			if os.IsNotExist(errors.Cause(err)) {
				return nil, ErrCgroupDeleted
			}
			if err == ErrControllerNotActive {
				if config.InitCheck != nil {
					if skerr := config.InitCheck(s, path, err); skerr != nil {
						if skerr != ErrIgnoreSubsystem {
							return nil, skerr
						}
					}
				}
				continue
			}
			return nil, err
		}
		if _, err := os.Lstat(s.Path(p)); err != nil {
			if os.IsNotExist(err) {
				continue
			}
			return nil, err
		}
		activeSubsystems = append(activeSubsystems, s)
	}
	if len(activeSubsystems) == 0 {
		return nil, ErrCgroupDeleted
	}
	return &cgroup{
		path:       path,
		subsystems: activeSubsystems,
	}, nil
}
type cgroup struct {
	path Path
	subsystems []Subsystem
	mu         sync.Mutex
	err        error
}
func (c *cgroup) New(name string, resources *specs.LinuxResources) (Cgroup, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err != nil {
		return nil, c.err
	}
	path := subPath(c.path, name)
	for _, s := range c.subsystems {
		if err := initializeSubsystem(s, path, resources); err != nil {
			return nil, err
		}
	}
	return &cgroup{
		path:       path,
		subsystems: c.subsystems,
	}, nil
}
func (c *cgroup) Subsystems() []Subsystem {
	return c.subsystems
}
func (c *cgroup) Add(process Process) error {
	if process.Pid <= 0 {
		return ErrInvalidPid
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err != nil {
		return c.err
	}
	return c.add(process)
}
func (c *cgroup) add(process Process) error {
	for _, s := range pathers(c.subsystems) {
		p, err := c.path(s.Name())
		if err != nil {
			return err
		}
		if err := retryingWriteFile(
			filepath.Join(s.Path(p), cgroupProcs),
			[]byte(strconv.Itoa(process.Pid)),
			defaultFilePerm,
		); err != nil {
			return err
		}
	}
	return nil
}
func (c *cgroup) AddTask(process Process) error {
	if process.Pid <= 0 {
		return ErrInvalidPid
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err != nil {
		return c.err
	}
	return c.addTask(process)
}
func (c *cgroup) addTask(process Process) error {
	for _, s := range pathers(c.subsystems) {
		p, err := c.path(s.Name())
		if err != nil {
			return err
		}
		if err := retryingWriteFile(
			filepath.Join(s.Path(p), cgroupTasks),
			[]byte(strconv.Itoa(process.Pid)),
			defaultFilePerm,
		); err != nil {
			return err
		}
	}
	return nil
}
func (c *cgroup) Delete() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err != nil {
		return c.err
	}
	var errs []string
	for _, s := range c.subsystems {
		if d, ok := s.(deleter); ok {
			sp, err := c.path(s.Name())
			if err != nil {
				return err
			}
			if err := d.Delete(sp); err != nil {
				errs = append(errs, string(s.Name()))
			}
			continue
		}
		if p, ok := s.(pather); ok {
			sp, err := c.path(s.Name())
			if err != nil {
				return err
			}
			path := p.Path(sp)
			if err := remove(path); err != nil {
				errs = append(errs, path)
			}
		}
	}
	if len(errs) > 0 {
		return fmt.Errorf("cgroups: unable to remove paths %s", strings.Join(errs, ", "))
	}
	c.err = ErrCgroupDeleted
	return nil
}
func (c *cgroup) Stat(handlers ...ErrorHandler) (*v1.Metrics, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err != nil {
		return nil, c.err
	}
	if len(handlers) == 0 {
		handlers = append(handlers, errPassthrough)
	}
	var (
		stats = &v1.Metrics{
			CPU: &v1.CPUStat{
				Throttling: &v1.Throttle{},
				Usage:      &v1.CPUUsage{},
			},
		}
		wg   = &sync.WaitGroup{}
		errs = make(chan error, len(c.subsystems))
	)
	for _, s := range c.subsystems {
		if ss, ok := s.(stater); ok {
			sp, err := c.path(s.Name())
			if err != nil {
				return nil, err
			}
			wg.Add(1)
			go func() {
				defer wg.Done()
				if err := ss.Stat(sp, stats); err != nil {
					for _, eh := range handlers {
						if herr := eh(err); herr != nil {
							errs <- herr
						}
					}
				}
			}()
		}
	}
	wg.Wait()
	close(errs)
	for err := range errs {
		return nil, err
	}
	return stats, nil
}
func (c *cgroup) Update(resources *specs.LinuxResources) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err != nil {
		return c.err
	}
	for _, s := range c.subsystems {
		if u, ok := s.(updater); ok {
			sp, err := c.path(s.Name())
			if err != nil {
				return err
			}
			if err := u.Update(sp, resources); err != nil {
				return err
			}
		}
	}
	return nil
}