@@ -12,6 +12,7 @@ import (
12
12
"path/filepath"
13
13
"runtime"
14
14
"strconv"
15
+ "strings"
15
16
"sync"
16
17
"time"
17
18
@@ -122,13 +123,96 @@ func (p *setnsProcess) signal(sig os.Signal) error {
122
123
return unix .Kill (p .pid (), s )
123
124
}
124
125
126
+ func affToUnix (str string ) (* unix.CPUSet , error ) {
127
+ s := new (unix.CPUSet )
128
+ for _ , r := range strings .Split (str , "," ) {
129
+ // Allow extra spaces around.
130
+ r = strings .TrimSpace (r )
131
+ // Allow empty elements (extra commas).
132
+ if r == "" {
133
+ continue
134
+ }
135
+ if r0 , r1 , found := strings .Cut (r , "-" ); found {
136
+ start , err := strconv .ParseUint (r0 , 10 , 32 )
137
+ if err != nil {
138
+ return nil , err
139
+ }
140
+ end , err := strconv .ParseUint (r1 , 10 , 32 )
141
+ if err != nil {
142
+ return nil , err
143
+ }
144
+ if start > end {
145
+ return nil , errors .New ("invalid range: " + r )
146
+ }
147
+ for i := int (start ); i <= int (end ); i ++ {
148
+ s .Set (i )
149
+ }
150
+ } else {
151
+ val , err := strconv .ParseUint (r , 10 , 32 )
152
+ if err != nil {
153
+ return nil , err
154
+ }
155
+ s .Set (int (val ))
156
+ }
157
+ }
158
+
159
+ return s , nil
160
+ }
161
+
162
+ // Starts setns process with specified initial CPU affinity.
163
+ func (p * setnsProcess ) startWithCPUAffinity () error {
164
+ aff := p .config .Config .ExecCPUAffinity
165
+ if aff == nil || aff .Initial == "" {
166
+ return p .cmd .Start ()
167
+ }
168
+ cpus , err := affToUnix (aff .Initial )
169
+ if err != nil {
170
+ return fmt .Errorf ("invalid execCPUAffinity.initial: %w" , err )
171
+ }
172
+
173
+ errCh := make (chan error )
174
+ defer close (errCh )
175
+
176
+ // Use a goroutine to dedicate an OS thread.
177
+ go func () {
178
+ // Don't call runtime.UnlockOSThread to terminate the OS thread
179
+ // when goroutine exits.
180
+ runtime .LockOSThread ()
181
+
182
+ // Command inherits the CPU affinity.
183
+ if err := unix .SchedSetaffinity (unix .Gettid (), cpus ); err != nil {
184
+ errCh <- fmt .Errorf ("setting initial CPU affinity: %w" , err )
185
+ return
186
+ }
187
+
188
+ errCh <- p .cmd .Start ()
189
+ }()
190
+
191
+ return <- errCh
192
+ }
193
+
194
+ func (p * setnsProcess ) setFinalCPUAffinity () error {
195
+ aff := p .config .Config .ExecCPUAffinity
196
+ if aff == nil || aff .Final == "" {
197
+ return nil
198
+ }
199
+ cpus , err := affToUnix (aff .Final )
200
+ if err != nil {
201
+ return fmt .Errorf ("invalid execCPUAffinity.final: %w" , err )
202
+ }
203
+ if err := unix .SchedSetaffinity (p .pid (), cpus ); err != nil {
204
+ return fmt .Errorf ("setting final CPU affinity: %w" , err )
205
+ }
206
+ return nil
207
+ }
208
+
125
209
func (p * setnsProcess ) start () (retErr error ) {
126
210
defer p .comm .closeParent ()
127
211
128
- // get the "before" value of oom kill count
212
+ // Get the "before" value of oom kill count.
129
213
oom , _ := p .manager .OOMKillCount ()
130
- err := p .cmd . Start () // https://github.com/opencontainers/runc/pull/3923/commits/afc23e33971b657c4a09c54b16c6139651171aad
131
- // close the child-side of the pipes (controlled by child)
214
+ err := p .startWithCPUAffinity ()
215
+ // Close the child-side of the pipes (controlled by child).
132
216
p .comm .closeChild ()
133
217
if err != nil {
134
218
return fmt .Errorf ("error starting setns process: %w" , err )
@@ -196,6 +280,9 @@ func (p *setnsProcess) start() (retErr error) {
196
280
}
197
281
}
198
282
}
283
+ if err := p .setFinalCPUAffinity (); err != nil {
284
+ return err
285
+ }
199
286
200
287
if err := utils .WriteJSON (p .comm .initSockParent , p .config ); err != nil {
201
288
return fmt .Errorf ("error writing config to pipe: %w" , err )
0 commit comments