How does CPU affinity interact with cgroups in Linux?

From the cpusets documentation:

Calls to sched_setaffinity are filtered to just those CPUs allowed in that task's cpuset.

This implies that CPU affinity masks are intersected with the cpus in the cgroup that the process is a member of.

E.g. If the affinity mask of a process includes cores {0, 1, 3} and the process is running on the system cgroup, which is restricted to cores {1, 2}, then the process would be forced to run on core 1.

I'm 99% certain that the htop output is "wrong" to the fact that the processes have not woken up since the cgroups were created, and the display is showing the last core the process ran on.

If I start vim before making my shield, vim forks twice (for some reason), and the deepest child is running on core 2. If I then make the shield, then sleep vim (ctrl+z) and wake it, both processes have moved to core 0. I think this confirms the hypothesis that htop is showing stale information.

You can also inspect /proc/<pid>/status and look at the cpus_allowed_* fields.

E.g. I have a console-kit-daemon process (pid 857) here showing in htop as running on core 3, but in /proc/857/status:

Cpus_allowed:   1
Cpus_allowed_list:      0

I think this is saying that the affinity mask is 0x1, which allows running on only core 1 due to the cgroups: i.e. intersect({0,1,2,3}, {0}) = {0}.

If I can, I'll leave the question open a while to see if any better answer comes up.

Thanks to @davmac for helping with this (on irc).