cmd_with has the wait loop for a semaphore slot, then a branch for sem-only that returns early, then the paths loop, with the release trap set up twice. One acquire_with_wait <kind> ... function and one release path would remove roughly 60 lines and the risk that a fix lands in one copy. The semaphore retry loop in sem_acquire_once/sem_release_once is a third copy of the same shape.
cmd_withhas the wait loop for a semaphore slot, then a branch for sem-only that returns early, then the paths loop, with the release trap set up twice. Oneacquire_with_wait <kind> ...function and one release path would remove roughly 60 lines and the risk that a fix lands in one copy. The semaphore retry loop insem_acquire_once/sem_release_onceis a third copy of the same shape.