Не кидайтесь тапками. Если абстрагироваться от понятия тредов и корутин, то мы имеет последовательность операций (слишком грубо называть потоком, согласен). Эта последовательность может быть прервана вызовом suspend функции (для вызова прерывания из функции она должна быть suspend). Естественно последовательность операций выполняется на потоке и получается что корутина - это слой абстракции над неким пулом (дефолтный размер = количеству 'ядер', доступных на машине). В момент прерывания этой последовательности происходит выггрузка стека корутины из потока и её сохранение в куче, после чего в поток загружается стек другой сопрограммы. Соответствующий байт-код генерируется компилятором Kotlin.