Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 16:02
Оценка:
Здравствуйте. Думаю, вопрос уже немало обсосан, но осмелюсь поднять очередную тему.
Реализовал сопрограммы используя WinAPI-функции SetThreadContext и GetThreadContext. Точнее, я подглядел как это сделал другой человек Он эмулировал ими стандартные POSIX-функции getcontext/setcontext/makecontext/swapcontext и потом, на их основе "возвел" класс сопрограммы. Все работает четко, но исключения не ловятся То есть если я внутри сопрограмммы напишу:
    try
    {
      throw 1;
    }
    catch(int)
    {
    },

то исключение не словится, будет unhadled exception. Это делает меня плакать, я о сопрограммах джва года мечтал Соответственно, вопросы знатокам:
1. Можно ли как-то "пропатчить" SetThreadContext и GetThreadContext чтобы исключения работали?
2. POSIX-функции getcontext/setcontext/makecontext/swapcontext на Unix-ах дружат с исключениями? Или вообще такой подход нежизнеспособен?
3. boost.Coroutines — стоящая вещь? Она делает хорошие портабельные и компактные сопрограммы? Или она тоже работает только в тепличных условиях?
4. Сопрограммы вообще могут быть портабельными в пределах Win32-Unix(MacOS)?
5. А как с мобильными платформами? Android дружит с этим? Он же вроде потомок Unix. А iOS?
Re: Сопрограммы и исключения.
От: ononim  
Дата: 27.09.11 16:25
Оценка:
W>Здравствуйте. Думаю, вопрос уже немало обсосан, но осмелюсь поднять очередную тему.
W>Реализовал сопрограммы используя WinAPI-функции SetThreadContext и GetThreadContext. Точнее, я подглядел как это сделал другой человек Он эмулировал ими стандартные POSIX-функции getcontext/setcontext/makecontext/swapcontext и потом, на их основе "возвел" класс сопрограммы. Все работает четко, но исключения не ловятся То есть если я внутри сопрограмммы напишу:
винда не ловит исключения если
1) цепочка SEH обработчиков, начинающаяся с _NT_TIB::ExceptionList невалидна
2) текущий esp не укладывается в _NT_TIB::StackBase/StackLimit
Как много веселых ребят, и все делают велосипед...
Re[2]: Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 16:52
Оценка:
Здравствуйте, ononim, Вы писали:

W>>Здравствуйте. Думаю, вопрос уже немало обсосан, но осмелюсь поднять очередную тему.

W>>Реализовал сопрограммы используя WinAPI-функции SetThreadContext и GetThreadContext. Точнее, я подглядел как это сделал другой человек Он эмулировал ими стандартные POSIX-функции getcontext/setcontext/makecontext/swapcontext и потом, на их основе "возвел" класс сопрограммы. Все работает четко, но исключения не ловятся То есть если я внутри сопрограмммы напишу:
O>винда не ловит исключения если
O>1) цепочка SEH обработчиков, начинающаяся с _NT_TIB::ExceptionList невалидна
O>2) текущий esp не укладывается в _NT_TIB::StackBase/StackLimit

То есть при входе в сопрограмму нужно модифицировать _NT_TIB::StackBase/StackLimit на новый стек, и как-то правильно построить _NT_TIB::ExceptionList? А как мне достучаться к "текущей" _NT_TIB? Я, вообще, не бред говорю?
Re[3]: Сопрограммы и исключения.
От: ononim  
Дата: 27.09.11 17:44
Оценка: 3 (1) +1
W>То есть при входе в сопрограмму нужно модифицировать _NT_TIB::StackBase/StackLimit на новый стек, и как-то правильно построить _NT_TIB::ExceptionList? А как мне достучаться к "текущей" _NT_TIB? Я, вообще, не бред говорю?
Не, не бред. Кстати, может вам нужны fiber'ы?
На x86 TEB лежит начиная с FS:[0], удобный адрес TEB в селекторе DS мона достать в FS::[18]
Как много веселых ребят, и все делают велосипед...
Re[3]: Сопрограммы и исключения.
От: Patalog Россия  
Дата: 27.09.11 17:59
Оценка: 2 (1)
Здравствуйте, Went, Вы писали:

[]

O>>1) цепочка SEH обработчиков, начинающаяся с _NT_TIB::ExceptionList невалидна

O>>2) текущий esp не укладывается в _NT_TIB::StackBase/StackLimit

W>То есть при входе в сопрограмму нужно модифицировать _NT_TIB::StackBase/StackLimit на новый стек, и как-то правильно построить _NT_TIB::ExceptionList? А как мне достучаться к "текущей" _NT_TIB? Я, вообще, не бред говорю? :)


Сделай свой обработчик VEH и диспатчи исключения в нем, поскольку VEH отрабатывает до SEH.
Что-то типа
__declspec (naked)
EXCEPTION_DISPOSITION __stdcall execute_handler2(PEXCEPTION_RECORD record, void* frame, PCONTEXT context,
                                                 PVOID dispatcher_context, PEXCEPTION_ROUTINE handler)
{
    __asm
    {
        push    ebp
        mov     ebp,esp
        push    dword ptr [dispatcher_context]
        push    dword ptr [context]
        push    dword ptr [frame]
        push    dword ptr [record]
        mov     ecx, dword ptr [handler]
        call    ecx                    
        mov     esp, ebp                
        pop     ebp                    
        ret     14h                    
    }
}

EXCEPTION_DISPOSITION __stdcall execute_handler(PEXCEPTION_RECORD record, void* frame,
                                                PCONTEXT context, PVOID dispatcher_context, PEXCEPTION_ROUTINE handler)
{ return execute_handler2(record, frame, context, dispatcher_context, handler); }

LONG CALLBACK VectoredHandler(EXCEPTION_POINTERS* info)
{
    void* teb = NtCurrentTeb();
    if (!teb)
        return EXCEPTION_CONTINUE_SEARCH;

    PEXCEPTION_REGISTRATION_RECORD exceptions =
        *reinterpret_cast<PEXCEPTION_REGISTRATION_RECORD*>(teb);
    if (!exceptions)
        return EXCEPTION_CONTINUE_SEARCH;

    while (exceptions != EXCEPTION_CHAIN_END)
    {
        DISPATCHER_CONTEXT dispatcher_context = {};

        EXCEPTION_DISPOSITION disposition =
            execute_handler(info->ExceptionRecord, exceptions, info->ContextRecord, &dispatcher_context, exceptions->Handler);

        switch (disposition)
        {
            case ExceptionContinueExecution:
                return EXCEPTION_CONTINUE_EXECUTION;

            case ExceptionContinueSearch:
                break;

            case ExceptionNestedException:
            case ExceptionCollidedUnwind:
                std::abort();

            default:
                assert(!"Unknown exception disposition.");
        }

        exceptions = exceptions->Next;
    }

    return EXCEPTION_CONTINUE_SEARCH;
}
Почетный кавалер ордена Совка.
Re: Сопрограммы и исключения.
От: niXman Ниоткуда https://github.com/niXman
Дата: 27.09.11 18:07
Оценка: 2 (1)
Здравствуйте, Went, Вы писали:
W>2. POSIX-функции getcontext/setcontext/makecontext/swapcontext на Unix-ах дружат с исключениями? Или вообще такой подход нежизнеспособен?
да. дружат. однажды использовал для подобной задачи. с исключениями проблем не было.

W>3. boost.Coroutines — стоящая вещь? Она делает хорошие портабельные и компактные сопрограммы? Или она тоже работает только в тепличных условиях?

да — портабельные. ибо не использует ничего платформозависимого. посмотри такую реализацию(читать именно с этом порядке):
http://blog.think-async.com/2009/07/wife-says-i-cant-believe-it-works.html
http://blog.think-async.com/2009/08/secret-sauce-revealed.html
http://blog.think-async.com/2009/08/composed-operations-coroutines-and-code.html
http://blog.think-async.com/2010/03/potted-guide-to-stackless-coroutines.html

"компактные" — это что? в каком смысле?

W>4. Сопрограммы вообще могут быть портабельными в пределах Win32-Unix(MacOS)?

да. см выше.

W>5. А как с мобильными платформами? Android дружит с этим? Он же вроде потомок Unix. А iOS?

см выше.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 18:43
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, Went, Вы писали:

W>>2. POSIX-функции getcontext/setcontext/makecontext/swapcontext на Unix-ах дружат с исключениями? Или вообще такой подход нежизнеспособен?
X>да. дружат. однажды использовал для подобной задачи. с исключениями проблем не было.
Это радует. Ибо на Win32 без допилки (спасибо ononim) не работало

W>>3. boost.Coroutines — стоящая вещь? Она делает хорошие портабельные и компактные сопрограммы? Или она тоже работает только в тепличных условиях?

X>да — портабельные. ибо не использует ничего платформозависимого. посмотри такую реализацию(читать именно с этом порядке):
X>http://blog.think-async.com/2009/07/wife-says-i-cant-believe-it-works.html
X>http://blog.think-async.com/2009/08/secret-sauce-revealed.html
X>http://blog.think-async.com/2009/08/composed-operations-coroutines-and-code.html
X>http://blog.think-async.com/2010/03/potted-guide-to-stackless-coroutines.html
Это очень мило Но хотелось бы настоящих сорутин, чтобы со стеком
А разве boost.Coroutines не используют ничего платформеннозависимого? Как они тогда стек двигают?

X>"компактные" — это что? в каком смысле?

Ну, чтобы не приходилось писать специальный синтаксис для функций. Как в приведенном выше примере.

W>>4. Сопрограммы вообще могут быть портабельными в пределах Win32-Unix(MacOS)?

X>да. см выше.


W>>5. А как с мобильными платформами? Android дружит с этим? Он же вроде потомок Unix. А iOS?

X>см выше.
Re[4]: Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 18:45
Оценка:
Здравствуйте, Patalog, Вы писали:

P>Сделай свой обработчик VEH и диспатчи исключения в нем, поскольку VEH отрабатывает до SEH.

То есть это способ руками обрабатывать исключения? Без try/catch ?
Re[4]: Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 18:50
Оценка:
Здравствуйте, ononim, Вы писали:

W>>То есть при входе в сопрограмму нужно модифицировать _NT_TIB::StackBase/StackLimit на новый стек, и как-то правильно построить _NT_TIB::ExceptionList? А как мне достучаться к "текущей" _NT_TIB? Я, вообще, не бред говорю?

O>Не, не бред. Кстати, может вам нужны fiber'ы?
O>На x86 TEB лежит начиная с FS:[0], удобный адрес TEB в селекторе DS мона достать в FS::[18]
Вот это да! Какие, оказывается, дебри можно потянуть из невинной функции __readfsdword! Действительно, если указать правильные _NT_TIB::StackBase/StackLimit до вызова функции SetThreadContext, а также обнулить для нового контекста _NT_TIB::ExceptionList, то все начинает ловиться! Огромное спасибо
Re: Сопрограммы и исключения.
От: watch-maker  
Дата: 27.09.11 19:02
Оценка: 2 (1)
Здравствуйте, Went, Вы писали:

W>1. Можно ли как-то "пропатчить" SetThreadContext и GetThreadContext чтобы исключения работали?

Не использовать SetThreadContext, а использовать CreateFiber.

W>2. POSIX-функции getcontext/setcontext/makecontext/swapcontext на Unix-ах дружат с исключениями?

Да

W>3. boost.Coroutines — стоящая вещь? Она делает хорошие портабельные и компактные сопрограммы? Или она тоже работает только в тепличных условиях?


Без поддержки со стороны компилятора сопрограммы в C++ реализовать полностью нельзя. Ну или настолько сложно, что этого никто ещё не сделал.
Типичная проблема как раз связана с обработкой исключений. Например, если оно было выброшено из одной из сопрограмм, то нужно передать его в другие параллельно работающие сопрограммы, завершить часть из них, учесть возможность, что исключение может поймать другая сопрограмма или, если этого не произошло, пробросить исключение в главный поток — это очень сложно без правки компилятора.
Частичная поддержка (без обработки сложных исключений) вполне возможна.

W>4. Сопрограммы вообще могут быть портабельными в пределах Win32-Unix(MacOS)?

С учетом предыдущих оговорок, вполне. У нас используется setcontext для Unix, fibers для Windows и setjmp для других странных платформ.

W>5. А как с мобильными платформами? Android дружит с этим? Он же вроде потомок Unix.

Android же вообще не unix.
Re[3]: Сопрограммы и исключения.
От: watch-maker  
Дата: 27.09.11 19:13
Оценка:
Здравствуйте, Went, Вы писали:

W>А разве boost.Coroutines не используют ничего платформеннозависимого? Как они тогда стек двигают?


Только платформозависимое и используют. Для каждой платформы (ОС + компилятор) пишется свой код с ассемблерными вставками и прочими ужасами. Потом при копиляции через define выбирается нужный участок, остальное игнорируется.
Re[5]: Сопрограммы и исключения.
От: Patalog Россия  
Дата: 27.09.11 19:14
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Patalog, Вы писали:


P>>Сделай свой обработчик VEH и диспатчи исключения в нем, поскольку VEH отрабатывает до SEH.

W>То есть это способ руками обрабатывать исключения? Без try/catch ?

Нет, это способ их диспатчить, поскольку штатный диспетчер не взлетает, скорее всего по тем причинам, которые озвучил ononim.
Кстати, /nosafeseh пробовал?
Почетный кавалер ордена Совка.
Re[4]: Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 19:35
Оценка:
Здравствуйте, watch-maker, Вы писали:

WM>Только платформозависимое и используют. Для каждой платформы (ОС + компилятор) пишется свой код с ассемблерными вставками и прочими ужасами. Потом при копиляции через define выбирается нужный участок, остальное игнорируется.

Вот и я про это. Просто мне из прошлого сообщения показалось, что niXman считает, что там нет ничего специфического.
Re: Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 19:38
Оценка:
Здравствуйте.

Короче, получилась такая вот милашка

#define _WIN32_WINNT 0x5000

#include <windows.h>
#include <boost/tuple/tuple.hpp>
#include <base/main.h>
#include <base/function.h>
#include "ucontext/ucontext.h"
#include <iostream>

namespace md {

//////////////////////////////////////////////////////////////////////////
// Сопрограмма
//////////////////////////////////////////////////////////////////////////

class Coroutine
{
public:
  // Исключение о завершении. Можно перехватить, но обязательно потом кинуть вновь!
  struct Terminate
  {
  };
  // Исполняемая функция. Можно что-то забиндить.
  typedef function<void()> Functor;
  // Состояние рутины
  enum State
  {
    s_ready,        // Готова, но не запущена
    s_running,      // Запущена (по крайней мере 1 раз побывала в функции)
    s_terminating,  // Ожидает разрушения
    s_done,         // Отработала
  };

  // Создать пустую сопрограмму. При вызове будет просто вхолостую возвращать ОК
  Coroutine()
    : m_state(s_ready)
    , m_suspended(false)
  {
  }

  // Создать сопрограмму с указаной функцией и размером стека
  Coroutine(const Functor& functor, Size stack_size = 16384)
    : m_functor(functor)
    , m_state(s_ready)
    , m_suspended(false)
  {
    m_stack.resize(stack_size);
  }

  // Копировать сопрограмму. Ход выполнения не скопируется.
  Coroutine(const Coroutine& other)
    : m_state(s_ready)
    , m_suspended(false)
    , m_functor(other.m_functor)
  {
    m_stack.resize(other.m_stack.size());
  }

  // Деструктор. Завершает сопрограмму.
  ~Coroutine()
  {
    terminate();
  }

  // Узнать, законечна ли процедура в сопрограмме.
  Bool done() const 
  {
    return m_state == s_done;
  }

  // Узнать, выполняется ли она в данный момент.
  Bool executing() const 
  {
    return std::find(s_launched_coroutines.begin(), s_launched_coroutines.end(), this) != s_launched_coroutines.end();
  }

  // Отработать сопрограмму на шаг.
  void resume()
  {
    // Пустая функция всегда идет вхолостую
    if (m_functor.empty())
      return;

    switch (m_state)
    {
    case s_done:
      // Если уже отработала, то ничего не делаем.
      return;
    case s_ready:
      // Если "готова", нужно создать новый контекст
      getcontext(&m_functor_jmp);
      m_functor_jmp.uc_stack.ss_sp = &m_stack.front();
      m_functor_jmp.uc_stack.ss_size = m_stack.size();
      m_functor_jmp.uc_link = &m_main_jmp;
      makecontext(&m_functor_jmp, (FunctionCast)&Coroutine::proxy_starter, 1, (Size)this);
      m_state = s_running;
      // no break
    case s_running:
    case s_terminating:
      // И продолжаем выполнение
      m_suspended = false;
      s_launched_coroutines.push_back(this);

      // Переключаем контекст на сопрограмму
      swapcontext(&m_main_jmp, &m_functor_jmp);

      if (m_suspended)
      {
        // Если завершена по suspend, то переключаем m_functor_jmp на тот, что был до suspend
        m_functor_jmp = m_supend_jmp;
      }
      else
      {
        // Иначе мы вышли нормальным образом. Значит done.
        m_state = s_done;
      }

      s_launched_coroutines.pop_back();

      break;
    }
  }

  // Получить текущую исполняемую сопрограмму.
  static Coroutine* current()
  {
    return s_launched_coroutines.empty() ? null : s_launched_coroutines.back();
  }

  // Принудительно завершить сопрограмму.
  void terminate()
  {
    if (m_state == s_running)
    {
      m_state = s_terminating;

      if (!executing())
        resume();
    }
  }

  // Завершить и переключить в состояение готовности.
  void reset()
  {
    terminate();

    m_state = s_ready;
  }

  // Завершить и установить новые параметры.
  void reset(const Functor& functor, Size stack_size = 16384)
  {
    terminate();

    m_functor = functor;
    m_stack.resize(stack_size);
    m_state = s_ready;
  }

  // Глобальный вызов заморозки текущей сопрограммы.
  static void suspend()
  {
    ASSERT(!s_launched_coroutines.empty());
    current()->real_suspender();
  }

  // Голобальный вызов прекращения текущей сопрограммы.
  static void quit()
  {
    ASSERT(!s_launched_coroutines.empty());
    throw Terminate();
  }

protected:
  typedef std::vector<U8> Stack;                  // Стек
  typedef void (*FunctionCast)();                 // Стандартная функция для makecontext
  typedef std::vector<Coroutine*> Coroutines;     // Стек текущих сопрограмм

  // Прокси-функция для вызова 
  static void proxy_starter(Size arg)
  {
    reinterpret_cast<Coroutine*>(arg)->real_starter();
  }

  // Корень сопрограммы
  void real_starter()
  {
    try
    {
      m_functor();
    }
    catch(Terminate)
    {
      // Нас попросили сдохнуть
    }

    // Остальные несловленные исключения вызовут "бабах". Это, наверное, неверно.
  }

  // Функция возврата из сопрограммы
  void real_suspender()
  {
    m_suspended = true;
    swapcontext(&m_supend_jmp, &m_main_jmp);

    // Если на входе узнаем, что нас просили сдохнуть, делаем это.
    if (m_state == s_terminating)
      throw Terminate();
  }

  Functor m_functor;    // Функция
  State   m_state;      // Состояние
  Bool    m_suspended;  // Флаг "вышли по ожиданию"

  Stack       m_stack;        // Стек сопрограммы
  ucontext_t  m_functor_jmp;  // Конекст перехода в функцию
  ucontext_t  m_main_jmp;     // Конекст возврата домой
  ucontext_t  m_supend_jmp;   // Контекст сохраненного прыжка обратно в функцию

  static Coroutines s_launched_coroutines;  // Стек сопрограмм
};

Coroutine::Coroutines Coroutine::s_launched_coroutines;

} // md

using namespace md;

void test()
{
  for (Int n = 0; n < 10; ++ n)
  {
    std::cout << n << std::endl;
    Coroutine::suspend();
  }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
{
  // Создали
  Coroutine test_coroutine(&test);

  // Прокручиваем, пока не закончится
  while (!test_coroutine.done())
    test_coroutine.resume();

  // Перезапустили
  test_coroutine.reset();

  // Прокрутили 3 раза
  test_coroutine.resume();
  test_coroutine.resume();
  test_coroutine.resume();

  // Принудительно завершили.
  test_coroutine.terminate();

  return 0;
}


Может у кого-то хватит терпения взглянуть и сказать какие могут быть проблемы? Пока что тестил на Win32
Re[2]: Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 19:44
Оценка:
Здравствуйте, watch-maker, Вы писали:

WM>Не использовать SetThreadContext, а использовать CreateFiber.

Ну, вроде помогла "магия" прямой записи в TIB

WM>Да



WM>Частичная поддержка (без обработки сложных исключений) вполне возможна.

Ну, это то что мне нужно.

WM>С учетом предыдущих оговорок, вполне. У нас используется setcontext для Unix, fibers для Windows и setjmp для других странных платформ.



WM>Android же вообще не unix.

Точно, он Linux. Но Linux тоже POSIX, поэтому на нем должны быть setcontext?
Re[2]: Сопрограммы и исключения.
От: watch-maker  
Дата: 27.09.11 19:52
Оценка:
Здравствуйте, Went, Вы писали:

W> какие могут быть проблемы? Пока что тестил на Win32

Как минимум отсутствует выравнивание стека. На x86-64 скорее всего упадёт, на x86 выравнивания оказывается достаточно, но, это как бы тоже без гарантий работы.
Re[3]: Сопрограммы и исключения.
От: watch-maker  
Дата: 27.09.11 19:57
Оценка:
Здравствуйте, Went, Вы писали:

WM>>Не использовать SetThreadContext, а использовать CreateFiber.

W>Ну, вроде помогла "магия" прямой записи в TIB
Жуть, конечно. К чёрту такую магию, fibers куда как лучше

WM>>Android же вообще не unix.

W>Точно, он Linux. Но Linux тоже POSIX, поэтому на нем должны быть setcontext?
Не, тут всё не так.
В Android используется ядро Linux, но и только. Оно недоступно извне, да даже до glibc доступа нет.
С таким же успехом можно поставить Windows на VirtualBox на Ubuntu и говорить, что Windows превратилась в unix-систему, — конечно же это не так, ведь из такой установки Windows получить доступ к ядру Linux нельзя, — там непреодалимый барьер, всё закрыто.
Re[3]: Сопрограммы и исключения.
От: Went  
Дата: 27.09.11 20:07
Оценка:
Здравствуйте, watch-maker, Вы писали:

WM>Как минимум отсутствует выравнивание стека. На x86-64 скорее всего упадёт, на x86 выравнивания оказывается достаточно, но, это как бы тоже без гарантий работы.


По какому базису его нужно выравнивать?
Re[4]: Сопрограммы и исключения.
От: watch-maker  
Дата: 27.09.11 20:21
Оценка: 2 (1)
Здравствуйте, Went, Вы писали:

W>Здравствуйте, watch-maker, Вы писали:


WM>>Как минимум отсутствует выравнивание стека. На x86-64 скорее всего упадёт, на x86 выравнивания оказывается достаточно, но, это как бы тоже без гарантий работы.


W>По какому базису его нужно выравнивать?

Зависит от процессора и используемых соглашений о вызове (что в свою очередь зависит от ОС и компилятора). Фактически сейчас достаточно выравнивать на границу 16 байт — это минимум для типичных вызовов в x86-64 и минимум для некоторых вызовов в x86.
Re: Сопрограммы и исключения.
От: 0xDEADBEEF Ниоткуда  
Дата: 27.09.11 20:43
Оценка: 2 (1)
Здравствуйте, Went, Вы писали:

W>Здравствуйте. Думаю, вопрос уже немало обсосан, но осмелюсь поднять очередную тему.

W>Реализовал сопрограммы используя WinAPI-функции SetThreadContext и GetThreadContext.
Неправильное решение. Используй CreateFiber и SwitchToFiber

W>1. Можно ли как-то "пропатчить" SetThreadContext и GetThreadContext чтобы исключения работали?

Для решения "CreateFiber" это не нужно — для SEH (и исключений MSVC) все будет работать "из коробки".
Единственное, что категорически не рекомендуется — это выпускать исключение из сопрограммы. То есть, функция сопрограммы толжна быть завернута в "try{}catch(...){/*ничего*/}"

W>2. POSIX-функции getcontext/setcontext/makecontext/swapcontext на Unix-ах дружат с исключениями? Или вообще такой подход нежизнеспособен?

Дружат, точнее DWARF-исключениям на них пофигу. А для SjLj-исключений (но это устаревшая архаика) придется малеха похачить.

W>3. boost.Coroutines — стоящая вещь? Она делает хорошие портабельные и компактные сопрограммы? Или она тоже работает только в тепличных условиях?

Не знаю.

W>4. Сопрограммы вообще могут быть портабельными в пределах Win32-Unix(MacOS)?

Да. Я реализовал достаточно мелкий класс для работы с сопрограммами. Работает на юнихах через setcontext, на выни — через CreateFiber. Исключения везде работают (даже SjLj, но это больше из любви к искусству).

W>5. А как с мобильными платформами? Android дружит с этим? Он же вроде потомок Unix. А iOS?

На андроиде — Жаба. Если хочется нативщины (и геморроя), то линух. То есть, setcontext должон работать.
__________
16.There is no cause so right that one cannot find a fool following it.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.