A UML context switch conceptually involves the running process stopping itself and continuing the incoming process.
The actual mechanism is different. Having the context switch actually doing kill(next, SIGCONT), kill(me, SIGSTOP) is unfixably racy. There have been several mechanisms over UML's history, but the current one involves the outgoing process writing a byte to a pipe being read by the incoming process. That wakes it up and starts it running. The outgoing process then reads its own pipe, causing it to sleep until another process switches back to it and writes a byte into that pipe.
The other major aspect of the context switch is that the incoming process must update its address space to reflect changes made while it was asleep. Pages may have been swapped out and must now be unmapped. Pages may have been write protected, so those protections need to be updated. This requires a scan of the entire address space looking for pages that need to be updated, which is slow.