@@ -61,11 +61,22 @@ const (
6161type Runc struct {
6262 // Command overrides the name of the runc binary. If empty, DefaultCommand
6363 // is used.
64- Command string
65- Root string
66- Debug bool
67- Log string
68- LogFormat Format
64+ Command string
65+ Root string
66+ Debug bool
67+ Log string
68+ LogFormat Format
69+ // PdeathSignal sets a signal the child process will receive when the
70+ // parent dies.
71+ //
72+ // When Pdeathsig is set, command invocations will call runtime.LockOSThread
73+ // to prevent OS thread termination from spuriously triggering the
74+ // signal. See https://github.com/golang/go/issues/27505 and
75+ // https://github.com/golang/go/blob/126c22a09824a7b52c019ed9a1d198b4e7781676/src/syscall/exec_linux.go#L48-L51
76+ //
77+ // A program with GOMAXPROCS=1 might hang because of the use of
78+ // runtime.LockOSThread. Callers should ensure they retain at least one
79+ // unlocked thread.
6980 PdeathSignal syscall.Signal // using syscall.Signal to allow compilation on non-unix (unix.Syscall is an alias for syscall.Signal)
7081 Setpgid bool
7182
@@ -83,7 +94,7 @@ type Runc struct {
8394
8495// List returns all containers created inside the provided runc root directory
8596func (r * Runc ) List (context context.Context ) ([]* Container , error ) {
86- data , err := cmdOutput (r .command (context , "list" , "--format=json" ), false , nil )
97+ data , err := r . cmdOutput (r .command (context , "list" , "--format=json" ), false , nil )
8798 defer putBuf (data )
8899 if err != nil {
89100 return nil , err
@@ -97,7 +108,7 @@ func (r *Runc) List(context context.Context) ([]*Container, error) {
97108
98109// State returns the state for the container provided by id
99110func (r * Runc ) State (context context.Context , id string ) (* Container , error ) {
100- data , err := cmdOutput (r .command (context , "state" , id ), true , nil )
111+ data , err := r . cmdOutput (r .command (context , "state" , id ), true , nil )
101112 defer putBuf (data )
102113 if err != nil {
103114 return nil , fmt .Errorf ("%s: %s" , err , data .String ())
@@ -157,6 +168,13 @@ func (o *CreateOpts) args() (out []string, err error) {
157168 return out , nil
158169}
159170
171+ func (r * Runc ) startCommand (cmd * exec.Cmd ) (chan Exit , error ) {
172+ if r .PdeathSignal != 0 {
173+ return Monitor .StartLocked (cmd )
174+ }
175+ return Monitor .Start (cmd )
176+ }
177+
160178// Create creates a new container and returns its pid if it was created successfully
161179func (r * Runc ) Create (context context.Context , id , bundle string , opts * CreateOpts ) error {
162180 args := []string {"create" , "--bundle" , bundle }
@@ -174,14 +192,14 @@ func (r *Runc) Create(context context.Context, id, bundle string, opts *CreateOp
174192 cmd .ExtraFiles = opts .ExtraFiles
175193
176194 if cmd .Stdout == nil && cmd .Stderr == nil {
177- data , err := cmdOutput (cmd , true , nil )
195+ data , err := r . cmdOutput (cmd , true , nil )
178196 defer putBuf (data )
179197 if err != nil {
180198 return fmt .Errorf ("%s: %s" , err , data .String ())
181199 }
182200 return nil
183201 }
184- ec , err := Monitor . Start (cmd )
202+ ec , err := r . startCommand (cmd )
185203 if err != nil {
186204 return err
187205 }
@@ -263,14 +281,14 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts
263281 opts .Set (cmd )
264282 }
265283 if cmd .Stdout == nil && cmd .Stderr == nil {
266- data , err := cmdOutput (cmd , true , opts .Started )
284+ data , err := r . cmdOutput (cmd , true , opts .Started )
267285 defer putBuf (data )
268286 if err != nil {
269287 return fmt .Errorf ("%w: %s" , err , data .String ())
270288 }
271289 return nil
272290 }
273- ec , err := Monitor . Start (cmd )
291+ ec , err := r . startCommand (cmd )
274292 if err != nil {
275293 return err
276294 }
@@ -309,7 +327,7 @@ func (r *Runc) Run(context context.Context, id, bundle string, opts *CreateOpts)
309327 if opts != nil && opts .IO != nil {
310328 opts .Set (cmd )
311329 }
312- ec , err := Monitor . Start (cmd )
330+ ec , err := r . startCommand (cmd )
313331 if err != nil {
314332 return - 1 , err
315333 }
@@ -382,7 +400,7 @@ func (r *Runc) Stats(context context.Context, id string) (*Stats, error) {
382400 if err != nil {
383401 return nil , err
384402 }
385- ec , err := Monitor . Start (cmd )
403+ ec , err := r . startCommand (cmd )
386404 if err != nil {
387405 return nil , err
388406 }
@@ -404,7 +422,7 @@ func (r *Runc) Events(context context.Context, id string, interval time.Duration
404422 if err != nil {
405423 return nil , err
406424 }
407- ec , err := Monitor . Start (cmd )
425+ ec , err := r . startCommand (cmd )
408426 if err != nil {
409427 rd .Close ()
410428 return nil , err
@@ -448,7 +466,7 @@ func (r *Runc) Resume(context context.Context, id string) error {
448466
449467// Ps lists all the processes inside the container returning their pids
450468func (r * Runc ) Ps (context context.Context , id string ) ([]int , error ) {
451- data , err := cmdOutput (r .command (context , "ps" , "--format" , "json" , id ), true , nil )
469+ data , err := r . cmdOutput (r .command (context , "ps" , "--format" , "json" , id ), true , nil )
452470 defer putBuf (data )
453471 if err != nil {
454472 return nil , fmt .Errorf ("%s: %s" , err , data .String ())
@@ -462,7 +480,7 @@ func (r *Runc) Ps(context context.Context, id string) ([]int, error) {
462480
463481// Top lists all the processes inside the container returning the full ps data
464482func (r * Runc ) Top (context context.Context , id string , psOptions string ) (* TopResults , error ) {
465- data , err := cmdOutput (r .command (context , "ps" , "--format" , "table" , id , psOptions ), true , nil )
483+ data , err := r . cmdOutput (r .command (context , "ps" , "--format" , "table" , id , psOptions ), true , nil )
466484 defer putBuf (data )
467485 if err != nil {
468486 return nil , fmt .Errorf ("%s: %s" , err , data .String ())
@@ -647,7 +665,7 @@ func (r *Runc) Restore(context context.Context, id, bundle string, opts *Restore
647665 if opts != nil && opts .IO != nil {
648666 opts .Set (cmd )
649667 }
650- ec , err := Monitor . Start (cmd )
668+ ec , err := r . startCommand (cmd )
651669 if err != nil {
652670 return - 1 , err
653671 }
@@ -691,7 +709,7 @@ type Version struct {
691709
692710// Version returns the runc and runtime-spec versions
693711func (r * Runc ) Version (context context.Context ) (Version , error ) {
694- data , err := cmdOutput (r .command (context , "--version" ), false , nil )
712+ data , err := r . cmdOutput (r .command (context , "--version" ), false , nil )
695713 defer putBuf (data )
696714 if err != nil {
697715 return Version {}, err
@@ -753,7 +771,7 @@ func (r *Runc) args() (out []string) {
753771// <stderr>
754772func (r * Runc ) runOrError (cmd * exec.Cmd ) error {
755773 if cmd .Stdout != nil || cmd .Stderr != nil {
756- ec , err := Monitor . Start (cmd )
774+ ec , err := r . startCommand (cmd )
757775 if err != nil {
758776 return err
759777 }
@@ -763,7 +781,7 @@ func (r *Runc) runOrError(cmd *exec.Cmd) error {
763781 }
764782 return err
765783 }
766- data , err := cmdOutput (cmd , true , nil )
784+ data , err := r . cmdOutput (cmd , true , nil )
767785 defer putBuf (data )
768786 if err != nil {
769787 return fmt .Errorf ("%s: %s" , err , data .String ())
@@ -773,14 +791,14 @@ func (r *Runc) runOrError(cmd *exec.Cmd) error {
773791
774792// callers of cmdOutput are expected to call putBuf on the returned Buffer
775793// to ensure it is released back to the shared pool after use.
776- func cmdOutput (cmd * exec.Cmd , combined bool , started chan <- int ) (* bytes.Buffer , error ) {
794+ func ( r * Runc ) cmdOutput (cmd * exec.Cmd , combined bool , started chan <- int ) (* bytes.Buffer , error ) {
777795 b := getBuf ()
778796
779797 cmd .Stdout = b
780798 if combined {
781799 cmd .Stderr = b
782800 }
783- ec , err := Monitor . Start (cmd )
801+ ec , err := r . startCommand (cmd )
784802 if err != nil {
785803 return nil , err
786804 }
0 commit comments