> А как они реализовали многозадачность на 8086?Проблем-то.
1. Запускаешь резидента, который выделяет себе кусок памяти и организовывает в нём список структур -- по инстансу структуры на выполняемую задачу. Называешь этот список структур очередью задач.
2. Из резидента вешаешь обработчик прерывания таймера.
3. Обработчик таймера находит структуру текущего процесса (если правильно организовать она будет первой в списке), сохраняет туда регистры, перемещает структуру в конец списка, берёт первую структуру из списка, восстанавливает регистры оттуда, iret.
Это базовая имплементация, которая не умеет в приоритеты процессов, которая не учитывает состояния процесса (процесс может ждать ввода/вывода -- нет смысла его будить в таком случае, а может даже можно сломать что-нибудь: разбуженный код может решить, например, что операция ввода/вывода сфейлилась), может ещё какие нюансы есть, я навскидку могу упустить что-то. Ах да, надо не забыть про сегментные регистры, их тоже надо все сохранять в структуры и восстанавливать оттуда. И да, CoW не получится запилить, придётся при fork'е создавать копию памяти процесса.
У неё есть недостаток: она засирает стек работающего процесса значениями CS:IP и FLAGS, которые туда складываются при прерывании. Но компиляторы, даже для юзерспейс кода, даже на архитектурах, которые обеспечивают каждому процессу индивидуальное адресное пространство, всё ж не используют стек выше указателя стека. Они не полагаются на то, что та память будет неизменной. Всякий код переключающий стеки может обидеться на такое, или какие-нибудь там защиты стека типа красных зон сломаются, но защиты можно отключить, а код переключающий стеки не запускать в такой системе, или переписать соответствующим образом.