func (pl *Proclist) Start(id string, opts *ProcOpts, attrs *map[string]interface{}) {
	if opts == nil {
		opts = &ProcOpts{
			StopCancelPanic: pl.opts.StopCancelPanic,
			ForbidCancel:    pl.opts.ForbidCancel,
		}
	}
	p := &proc{
		id:   id,
		opts: *opts,
	}
	if attrs != nil {
		p.attrs = *attrs
	} else {
		p.attrs = make(map[string]interface{})
	}
	p.addHistoryEntry(time.Now(), "init")
	pl.mu.Lock()
	if pl.procs == nil {
		pl.procs = make(map[string]*proc)
	}
	pl.procs[id] = p
	pl.mu.Unlock()
}
Start marks the beginning of a task at this Proclist. All attributes are
recorded but not handled internally by the package. They will be mapped to
JSON and provided to HTTP clients for this task. It's the caller's
responsibility to provide different identifiers for separate tasks. An id can
only be reused after the task previously using it is over. If process options
are not provided (nil), Start() will snapshot the global options for the
process list set by SetOptions().
package pm
import (
	"container/list"
	"errors"
	"sync"
	"time"
)
type Proclist struct {
	mu    sync.RWMutex
	procs map[string]*proc
	opts  ProclistOpts
}
type ProclistOpts struct {
	StopCancelPanic bool  
	ForbidCancel    bool  
}
type ProcOpts struct {
	StopCancelPanic bool  
	ForbidCancel    bool  
}
type proc struct {
	mu      sync.RWMutex
	id      string
	attrs   map[string]interface{}
	history list.List
	cancel  struct {
		isPending bool
		message   string
	}
	opts ProcOpts
}
type historyEntry struct {
	ts     time.Time
	status string
}
var (
	ErrForbidden     = errors.New("forbidden")
	ErrNoSuchProcess = errors.New("no such process")
)
func (pl *Proclist) Options() ProclistOpts {
	pl.mu.RLock()
	defer pl.mu.RUnlock()
	return pl.opts
}
func (pl *Proclist) SetOptions(opts ProclistOpts) {
	pl.mu.Lock()
	defer pl.mu.Unlock()
	pl.opts = opts
}