Hello,
Manolo de Medici, le lun. 13 avril 2026 00:04:22 +0100, a ecrit:
> diff --git a/kern/machine.c b/kern/machine.c
> index f1380367..e730434d 100644
> --- a/kern/machine.c
> +++ b/kern/machine.c
> @@ -233,6 +233,64 @@ processor_request_action(
> thread_wakeup((event_t)&action_queue);
> }
>
> +
> +/*
> + * thread_would_hang() helper function for thread_shutdown and
> + * thread_assign operations.
> + *
> + * Refuse shutdown if it would strand any affinity-constrained thread in
> + * this processor set.
> + *
> + * Walk the pset thread queue and, for each thread whose affinity mask
> + * currently admits the processor being shut down, verify that some other
> + * processor in the same pset also satisfies that mask.
> + *
> + * If no alternate eligible processor exists, shutting this processor down
> + * would leave that thread without any runnable CPU in the pset, so abort
> + * the operation.
> + */
> +static
> +thread_t
> +thread_would_hang(
> + processor_t processor)
> +{
> + processor_set_t pset;
> + thread_t thread;
> + processor_t p;
> +
> + pset = processor->processor_set;
> + pset_lock(pset);
> +
> + queue_iterate(&pset->threads, thread, thread_t, pset_threads) {
> + thread_lock(thread);
> +
> + if (thread->has_affinity &&
> + cpu_affinity_test(&thread->affinity, processor->slot_num)) {
> +
> + queue_iterate(&pset->processors, p, processor_t, processors) {
> + if (p == processor)
> + continue;
> +
> + if (cpu_affinity_test(&thread->affinity, p->slot_num)) {
> + goto thread_can_run;
> + }
This ends up quite quadratic.
We can probably rather first compute a cpu_affinity_t mask that contains
all the processor ids of the pset, drop the processor being removed from
it, and then go over threads and quickly "and" the mask with the thread
affinity mask to check that it's not empty.
> + }
> +
> + thread_unlock(thread);
> + pset_unlock(pset);
> +
> + return thread;
> + }
> +
> +thread_can_run:
> + thread_unlock(thread);
> + }
> +
> + pset_unlock(pset);
> +
> + return THREAD_NULL;
> +}
> +
> #if MACH_HOST
> /*
> * processor_assign() changes the processor set that a processor is
> diff --git a/kern/thread.c b/kern/thread.c
> index deb9688d..f00304b2 100644
> --- a/kern/thread.c
> +++ b/kern/thread.c
> +/*
> + *
> + * thread_set_affinity
> + *
> + * Set thread affinity, the procs array contains the target CPUs.
> + * A NULL array indicates to clear affinity and set default.
> + * Returns an error if any CPU is outside of the thread processor set.
> + *
> + * If the thread is currently executing, it may wait until its time slice
> + * is up before switching onto the specified processor.
> + *
> + */
> +kern_return_t
> +thread_set_affinity(
> + thread_t thread,
> + processor_name_array_t processor_list,
> + natural_t countp)
> +{
> + cpu_affinity_t newmask;
> + processor_t p;
> + int i;
> + boolean_t any = FALSE;
> + spl_t s;
> +
> + if (thread == THREAD_NULL)
> + return KERN_INVALID_ARGUMENT;
> +
> + if (processor_list == NULL || countp == 0) {
> + thread->has_affinity = FALSE;
> + return KERN_SUCCESS;
> + }
> +
> + cpu_affinity_zero(&newmask);
> +
> + thread_lock(thread);
> + pset_lock(thread->processor_set);
> +
> + for (i = 0; i < countp; i++) {
> + p = convert_port_to_processor_name(
> + (ipc_port_t)processor_list[i]);
> +
> + if (p == PROCESSOR_NULL)
> + continue;
> +
> + cpu_affinity_set(&newmask, (unsigned)p->slot_num);
> +
> + /* reaquire at least one processor in the correct pset */
> + if (p->processor_set != thread->processor_set)
> + continue;
> +
> + any = TRUE;
This test looks a bit reverse to me, better make it
/* require at least one processor in the correct pset */
if (p->processor_set == thread->processor_set)
any = TRUE;
But didn't we want to actually error out completely if userland passes
processor numbers that are not part of the thread current pset?
> + }
> +
> + if (!any) {
> + pset_unlock(thread->processor_set);
> + thread_unlock(thread);
> + return KERN_INVALID_ARGUMENT; /* empty effective set */
> + }
> +
> + thread->affinity = newmask;
> + thread->has_affinity = TRUE;
> +
> + s = splsched();
> + thread_enforce_affinity(thread);
> + splx(s);
> +
> + pset_unlock(thread->processor_set);
> + thread_unlock(thread);
> +
> + return KERN_SUCCESS;
> +}
> diff --git a/kern/thread.h b/kern/thread.h
> index e5128dad..2e5ceb47 100644
> --- a/kern/thread.h
> +++ b/kern/thread.h
> +static inline void
> +cpu_affinity_set(cpu_affinity_t *m, unsigned cpu) {
> + m->bits[cpu >> 5] |= (1u << (cpu & 31));
Better use / 32 rather than >> 5 which is a bit more cryptic.
> +static inline unsigned int
> +popcnt_uint32(uint32_t n) {
> + unsigned int count = 0;
> +
> + while (n) {
> + n &= n - 1;
> + count++;
> + }
> +
> + return count;
> +}
We can use __builtin_popcount instead