IO can happen by message queue that thee OS looks at from time to time, context switching can be initiated by a lot of algorithms that don't need to invalidate your pipeline state, and OS calls can be entirely synchronous.
Interruptions are mostly a bad legacy from the time our computers were slow, kept around for compatibility reasons.
A core that is otherwise sleeping, an instruction countdown, a synchronous microinstruction that does some "finish this and jump if the list is non-empty" triggered by a timer...
There is a lot of stuff implied by an interruption. Computers need some of them for some functions, but never the entire lot.
Interruptions are mostly a bad legacy from the time our computers were slow, kept around for compatibility reasons.