func subRLock(l *namedLocker) (io.WriteCloser, io.ReadCloser, error) {
	cmd := reexec.Command("subRLock", l.name)
	wc, err := cmd.StdinPipe()
	if err != nil {
		return nil, nil, err
	}
	rc, err := cmd.StdoutPipe()
	if err != nil {
		return nil, nil, err
	}
	go func() {
		if err = cmd.Run(); err != nil {
			logrus.Errorf("Running subRLock: %v", err)
		}
	}()
	return wc, rc, nil
}
subRLock starts a child process.  If it doesn't return an error, the caller
should wait for the first ReadCloser by reading it until it receives an EOF.
At that point, the child will have acquired a read lock.  It can then signal
that the child should release the lock by closing the WriteCloser.
package lockfile
import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sync"
	"sync/atomic"
	"testing"
	"time"
	"github.com/containers/storage/pkg/reexec"
	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
	if reexec.Init() {
		return
	}
	os.Exit(m.Run())
}
func subTouchMain() {
	if len(os.Args) != 2 {
		logrus.Fatalf("expected two args, got %d", len(os.Args))
	}
	tf, err := GetLockfile(os.Args[1])
	if err != nil {
		logrus.Fatalf("error opening lock file %q: %v", os.Args[1], err)
	}
	tf.Lock()
	os.Stdout.Close()
	io.Copy(ioutil.Discard, os.Stdin)
	tf.Touch()
	tf.Unlock()
}
func subTouch(l *namedLocker) (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) {
	cmd := reexec.Command("subTouch", l.name)
	wc, err := cmd.StdinPipe()
	if err != nil {
		return nil, nil, nil, err
	}
	rc, err := cmd.StdoutPipe()
	if err != nil {
		return nil, nil, nil, err
	}
	ec, err := cmd.StderrPipe()
	if err != nil {
		return nil, nil, nil, err
	}
	go func() {
		if err = cmd.Run(); err != nil {
			logrus.Errorf("Running subTouch: %v", err)
		}
	}()
	return wc, rc, ec, nil
}
func subLockMain() {
	if len(os.Args) != 2 {
		logrus.Fatalf("expected two args, got %d", len(os.Args))
	}
	tf, err := GetLockfile(os.Args[1])
	if err != nil {
		logrus.Fatalf("error opening lock file %q: %v", os.Args[1], err)
	}
	tf.Lock()
	os.Stdout.Close()
	io.Copy(ioutil.Discard, os.Stdin)
	tf.Unlock()
}
func subLock(l *namedLocker) (io.WriteCloser, io.ReadCloser, error) {
	cmd := reexec.Command("subLock", l.name)
	wc, err := cmd.StdinPipe()
	if err != nil {
		return nil, nil, err
	}
	rc, err := cmd.StdoutPipe()
	if err != nil {
		return nil, nil, err
	}
	go func() {
		if err = cmd.Run(); err != nil {
			logrus.Errorf("Running subLock: %v", err)
		}
	}()
	return wc, rc, nil
}
func subRecursiveLockMain() {
	if len(os.Args) != 2 {
		logrus.Fatalf("expected two args, got %d", len(os.Args))
	}
	tf, err := GetLockfile(os.Args[1])
	if err != nil {
		logrus.Fatalf("error opening lock file %q: %v", os.Args[1], err)
	}
	tf.RecursiveLock()
	os.Stdout.Close()
	io.Copy(ioutil.Discard, os.Stdin)
	tf.Unlock()
}
func subRecursiveLock(l *namedLocker) (io.WriteCloser, io.ReadCloser, error) {
	cmd := reexec.Command("subRecursiveLock", l.name)
	wc, err := cmd.StdinPipe()
	if err != nil {
		return nil, nil, err
	}
	rc, err := cmd.StdoutPipe()
	if err != nil {
		return nil, nil, err
	}
	go func() {
		if err = cmd.Run(); err != nil {
			logrus.Errorf("Running subLock: %v", err)
		}
	}()
	return wc, rc, nil
}
func subRLockMain() {
	if len(os.Args) != 2 {
		logrus.Fatalf("expected two args, got %d", len(os.Args))
	}
	tf, err := GetLockfile(os.Args[1])
	if err != nil {
		logrus.Fatalf("error opening lock file %q: %v", os.Args[1], err)
	}
	tf.RLock()
	os.Stdout.Close()
	io.Copy(ioutil.Discard, os.Stdin)
	tf.Unlock()
}