@@ -163,13 +163,63 @@ type setnsProcess struct {
163
163
initProcessPid int
164
164
}
165
165
166
+ // Starts setns process with specified initial CPU affinity.
167
+ func (p * setnsProcess ) startWithCPUAffinity () error {
168
+ aff := p .config .CPUAffinity
169
+ if aff == nil || aff .Initial == "" {
170
+ return p .cmd .Start ()
171
+ }
172
+ logrus .Debugf ("Initial CPU affinity: %s" , aff .Initial )
173
+ cpus , err := configs .ToCPUSet (aff .Initial )
174
+ if err != nil {
175
+ return fmt .Errorf ("invalid CPUAffinity.initial: %w" , err )
176
+ }
177
+
178
+ errCh := make (chan error )
179
+ defer close (errCh )
180
+
181
+ // Use a goroutine to dedicate an OS thread.
182
+ go func () {
183
+ runtime .LockOSThread ()
184
+ // Command inherits the CPU affinity.
185
+ if err := unix .SchedSetaffinity (unix .Gettid (), cpus ); err != nil {
186
+ runtime .UnlockOSThread ()
187
+ errCh <- fmt .Errorf ("setting initial CPU affinity: %w" , err )
188
+ return
189
+ }
190
+
191
+ errCh <- p .cmd .Start ()
192
+ // Deliberately omit runtime.UnlockOSThread here.
193
+ // https://pkg.go.dev/runtime#LockOSThread says:
194
+ // "If the calling goroutine exits without unlocking the
195
+ // thread, the thread will be terminated".
196
+ }()
197
+
198
+ return <- errCh
199
+ }
200
+
201
+ func (p * setnsProcess ) setFinalCPUAffinity () error {
202
+ aff := p .config .CPUAffinity
203
+ if aff == nil || aff .Final == "" {
204
+ return nil
205
+ }
206
+ cpus , err := configs .ToCPUSet (aff .Final )
207
+ if err != nil {
208
+ return fmt .Errorf ("invalid CPUAffinity.final: %w" , err )
209
+ }
210
+ if err := unix .SchedSetaffinity (p .pid (), cpus ); err != nil {
211
+ return fmt .Errorf ("setting final CPU affinity: %w" , err )
212
+ }
213
+ return nil
214
+ }
215
+
166
216
func (p * setnsProcess ) start () (retErr error ) {
167
217
defer p .comm .closeParent ()
168
218
169
- // get the "before" value of oom kill count
219
+ // Get the "before" value of oom kill count.
170
220
oom , _ := p .manager .OOMKillCount ()
171
- err := p .cmd . Start ()
172
- // close the child-side of the pipes (controlled by child)
221
+ err := p .startWithCPUAffinity ()
222
+ // Close the child-side of the pipes (controlled by child).
173
223
p .comm .closeChild ()
174
224
if err != nil {
175
225
return fmt .Errorf ("error starting setns process: %w" , err )
@@ -228,6 +278,9 @@ func (p *setnsProcess) start() (retErr error) {
228
278
}
229
279
}
230
280
}
281
+ if err := p .setFinalCPUAffinity (); err != nil {
282
+ return err
283
+ }
231
284
232
285
if err := utils .WriteJSON (p .comm .initSockParent , p .config ); err != nil {
233
286
return fmt .Errorf ("error writing config to pipe: %w" , err )
0 commit comments