Ejemplo n.º 1
0
VOID CALLBACK Fiber_Function(LPVOID param)
{
  pthread_t self = (pthread_t) param;
  thread_or_fiber_function(param);
  {
    /* fiber_group is a main thread into which we are to call */
    pthread_t group = self->fiber_group;
    free(self);
    /* pthread_np_run_in_fiber (see below) normally switches back to
       caller. Nullify our identity, so it knows there is nothing to
       switch to, and continues running instead. */
    tls_impersonate(NULL);
    if (group) {
      /* Every running [pthread_create]d fiber runs in some thread
         that has its own pthread_self identity (that was created as
         thread and later converted to fiber). `group' field of
         running fiber always points to that other pthread.

         Now switch to our group ("current master fiber created as
         thread"), asking it to delete our (OS) fiber data with
         fiber_destructor. */
      pthread_np_run_in_fiber(group, fiber_destructor, GetCurrentFiber());
    }
    /* Within current pthread API we never end up here.

     BTW, if fibers are ever pooled, to avoid stack space reallocation
     etc, jumping to the beginning of Fiber_Function should be the
     thing to do here. */
    DeleteFiber(GetCurrentFiber()); /* Exits. See Thread_Function for
                                       explanation -- why not
                                       ExitThread. */
  }
}
Ejemplo n.º 2
0
FiberPool_::coro_pull_interface* FiberPool_::getFiber(size_t size, void** sp, coro_handler h, void* param /*= NULL*/)
{
	assert(size && size % 4096 == 0 && size <= 1024 * 1024);
	void* currentFiber = NULL;
#if _WIN32_WINNT >= 0x0600
	if (IsThreadAFiber())
	{
		currentFiber = GetCurrentFiber();
	}
	else
	{
		currentFiber = ConvertThreadToFiberEx(NULL, FIBER_FLAG_FLOAT_SWITCH);
	}
#else//#elif _MSC_VER >= 0x0501
	currentFiber = ConvertThreadToFiberEx(NULL, FIBER_FLAG_FLOAT_SWITCH);
	if (!currentFiber)
	{
		currentFiber = GetCurrentFiber();
	}
#endif
	{
		fiber_pool_pck& pool = s_fiberPool._fiberPool[size / 4096 - 1];
		pool._mutex.lock();
		if (!pool._pool.empty())
		{
			coro_pull_interface* oldFiber = pool._pool.back();
			pool._pool.pop_back();
			pool._mutex.unlock();
			oldFiber->_fiber._pushHandle = currentFiber;
			oldFiber->_fiber._currentHandler = h;
			oldFiber->_fiber._fiberHandle->_param = param;
			oldFiber->_fiber._tick = 0;
			*sp = oldFiber->_fiber._fiberHandle->_stackTop;
			SwitchToFiber(oldFiber->_fiber._fiberHandle);
			return oldFiber;
		}
		pool._mutex.unlock();
	}
	s_fiberPool._stackCount++;
	s_fiberPool._stackTotalSize += size;
	coro_pull_interface* newFiber = new coro_pull_interface;
#ifdef _WIN64
	newFiber->_fiber._fiberHandle = (FiberStruct_*)CreateFiberEx(size, 64 * 1024, FIBER_FLAG_FLOAT_SWITCH, FiberPool_::fiberHandler, newFiber);
#else
	newFiber->_fiber._fiberHandle = (FiberStruct_*)CreateFiberEx(size, 0, FIBER_FLAG_FLOAT_SWITCH, FiberPool_::fiberHandler, newFiber);
#endif
	if (newFiber->_fiber._fiberHandle)
	{
		newFiber->_fiber._pushHandle = currentFiber;
		newFiber->_fiber._currentHandler = h;
		newFiber->_fiber._fiberHandle->_param = param;
		newFiber->_fiber._tick = 0;
		*sp = newFiber->_fiber._fiberHandle->_stackTop;
		SwitchToFiber(newFiber->_fiber._fiberHandle);
		return newFiber;
	}
	delete newFiber;
	throw std::shared_ptr<string>(new string("Fiber不足"));
}
Ejemplo n.º 3
0
Archivo: Coro.c Proyecto: doublec/io
void Coro_initializeMainCoro(Coro *self)
{
	self->isMain = 1;
#ifdef USE_FIBERS
	// We must convert the current thread into a fiber if it hasn't already been done.
	if ((LPVOID) 0x1e00 == GetCurrentFiber()) // value returned when not a fiber
	{
		// Make this thread a fiber and set its data field to the main coro's address
		ConvertThreadToFiber(self);
	}
	// Make the main coro represent the current fiber
	self->fiber = GetCurrentFiber();
#endif
}
Ejemplo n.º 4
0
std::size_t TcpConnection::write(const uint8_t* data, size_t size) {
  assert(dispatcher != nullptr);
  assert(writeContext == nullptr);
  if (stopped) {
    throw InterruptedException();
  }

  if (size == 0) {
    if (shutdown(connection, SD_SEND) != 0) {
      throw std::runtime_error("TcpConnection::write, shutdown failed, result=" + std::to_string(WSAGetLastError()));
    }

    return 0;
  }

  WSABUF buf{static_cast<ULONG>(size), reinterpret_cast<char*>(const_cast<uint8_t*>(data))};
  TcpConnectionContext context;
  context.hEvent = NULL;
  if (WSASend(connection, &buf, 1, NULL, 0, &context, NULL) != 0) {
    int lastError = WSAGetLastError();
    if (lastError != WSA_IO_PENDING) {
      throw std::runtime_error("TcpConnection::write, WSASend failed, result=" + std::to_string(lastError));
    }
  }

  context.context = GetCurrentFiber();
  context.interrupted = false;
  writeContext = &context;
  dispatcher->dispatch();
  assert(context.context == GetCurrentFiber());
  assert(dispatcher != nullptr);
  assert(writeContext == &context);
  writeContext = nullptr;
  DWORD transferred;
  DWORD flags;
  if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) {
    int lastError = WSAGetLastError();
    if (lastError != ERROR_OPERATION_ABORTED) {
      throw std::runtime_error("TcpConnection::write, WSASend failed, result=" + std::to_string(lastError));
    }

    assert(context.interrupted);
    throw InterruptedException();
  }

  assert(transferred == size);
  assert(flags == 0);
  return transferred;
}
Ejemplo n.º 5
0
      /*
       * Free function. Saves the current context in @p from
       * and restores the context in @p to. On windows the from
       * parameter is ignored. The current context is saved on the
       * current fiber.
       * Note that if the current thread is not a fiber, it will be
       * converted to fiber on the fly on call and unconverted before
       * return. This is expensive. The user should convert the
       * current thread to a fiber once on thread creation for better performance.
       * Note that we can't leave the thread unconverted on return or else we
       * will leak resources on thread destruction. Do the right thing by
       * default.
       */
      friend
      void
      swap_context(fibers_context_impl_base& from,
                   const fibers_context_impl_base& to,
                   default_hint)
      {
        if(!is_fiber()) {
          HPX_ASSERT(from.m_ctx == 0);
          from.m_ctx = ConvertThreadToFiber(0);
          HPX_ASSERT(from.m_ctx != 0);

#if HPX_HAVE_SWAP_CONTEXT_EMULATION != 0
          switch_to_fiber(to.m_ctx);
#else
          SwitchToFiber(to.m_ctx);
#endif
          BOOL result = ConvertFiberToThread();
          HPX_ASSERT(result);
          HPX_UNUSED(result);
          from.m_ctx = 0;
        } else {
          bool call_from_main = from.m_ctx == 0;
          if(call_from_main)
            from.m_ctx = GetCurrentFiber();
#if HPX_HAVE_SWAP_CONTEXT_EMULATION != 0
          switch_to_fiber(to.m_ctx);
#else
          SwitchToFiber(to.m_ctx);
#endif
          if(call_from_main)
            from.m_ctx = 0;
        }
      }
Ejemplo n.º 6
0
void Coroutine::init()
{
	if (!IsThreadAFiber())
		pImpl->pReturnFiber = ConvertThreadToFiber(NULL);
	else 
		pImpl->pReturnFiber = GetCurrentFiber();
	pImpl->pFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)Coroutine::Anonymous::coroutineEntry, pImpl.get());
}
Ejemplo n.º 7
0
    /*
     * Return true if current thread is a fiber.
     */
    inline bool is_fiber() {
#if _WIN32_WINNT >= 0x0600
      return IsThreadAFiber() ? true : false;
#else
      fiber_ptr current = GetCurrentFiber();
      return current != 0 && current != fiber_magic;
#endif
    }
Ejemplo n.º 8
0
        void Return()
        {
            ESS_ASSERT( GetCurrentFiber() == m_handle );

            ESS_ASSERT( m_fiberToReturn != 0);
            LPVOID ret = m_fiberToReturn;
            m_fiberToReturn = 0;
            SwitchToFiber(ret);
        }
sc_cor_fiber::~sc_cor_fiber()
{
    if( m_fiber != 0 ) {
#     ifdef WIN32
      PVOID cur_fiber = GetCurrentFiber();
      if (m_fiber != cur_fiber)
#     endif
	DeleteFiber( m_fiber );
    }
}
Ejemplo n.º 10
0
void ReentrantLock::unlock() 
{
    if (owner == GetCurrentFiber()) {
        if (holdCount != 0) {
            holdCount--;
        } else {
            SimpleLock::unlock();
        }
    }
}
Ejemplo n.º 11
0
 static void MainThreadInit()
 {            
     PVOID pData = GetCurrentFiber();
     if (pData == (void*)0x1E00)  // magic
     {
         LPVOID h = ConvertThreadToFiber( &MainFiberId );
         ESS_ASSERT(h != 0);
         ESS_ASSERT( GetFiberData() == &MainFiberId );
     }
 }
Ejemplo n.º 12
0
        void Run()
        {
            ESS_ASSERT(m_fiberToReturn == 0);

            m_fiberToReturn = GetCurrentFiber();
            ESS_ASSERT(m_fiberToReturn != 0);
            ESS_ASSERT(m_fiberToReturn != m_handle);

            SwitchToFiber(m_handle);
        }
Ejemplo n.º 13
0
size_t TcpConnection::read(uint8_t* data, size_t size) {
  assert(dispatcher != nullptr);
  assert(readContext == nullptr);
  if (stopped) {
    throw InterruptedException();
  }

  WSABUF buf{static_cast<ULONG>(size), reinterpret_cast<char*>(data)};
  DWORD flags = 0;
  TcpConnectionContext context;
  context.hEvent = NULL;
  if (WSARecv(connection, &buf, 1, NULL, &flags, &context, NULL) != 0) {
    int lastError = WSAGetLastError();
    if (lastError != WSA_IO_PENDING) {
      throw std::runtime_error("TcpConnection::read, WSARecv failed, result=" + std::to_string(lastError));
    }
  }

  assert(flags == 0);
  context.context = GetCurrentFiber();
  context.interrupted = false;
  readContext = &context;
  dispatcher->dispatch();
  assert(context.context == GetCurrentFiber());
  assert(dispatcher != nullptr);
  assert(readContext == &context);
  readContext = nullptr;
  DWORD transferred;
  if (WSAGetOverlappedResult(connection, &context, &transferred, FALSE, &flags) != TRUE) {
    int lastError = WSAGetLastError();
    if (lastError != ERROR_OPERATION_ABORTED) {
      throw std::runtime_error("TcpConnection::read, WSARecv failed, result=" + std::to_string(lastError));
    }

    assert(context.interrupted);
    throw InterruptedException();
  }

  assert(transferred <= size);
  assert(flags == 0);
  return transferred;
}
Ejemplo n.º 14
0
void dpy_flushkeys(void)
{
	if (GetCurrentFiber() == uifiber)
	{
		while (numqueued)
		{
			currentkey = dequeue();
			SwitchToFiber(appfiber);
		}
	}
}
Ejemplo n.º 15
0
void Dispatcher::contextProcedure() {
  assert(GetCurrentThreadId() == threadId);
  for (;;) {
    assert(!spawningProcedures.empty());
    std::function<void()> procedure = std::move(spawningProcedures.front());
    spawningProcedures.pop();
    procedure();
    reusableContexts.push(GetCurrentFiber());
    dispatch();
  }
}
Ejemplo n.º 16
0
void ReentrantLock::lock() 
{
    // Если текущий фибер уже владеет блокировкой, 
    // то увеличиваем счетчик, иначе ожидаем освобождения блокировки.
    if (owner == GetCurrentFiber()) {
        holdCount++;
    } else {
        SimpleLock::lock();
        initNewOwner();
    }
}
Ejemplo n.º 17
0
void Dispatcher::yield() {
  assert(GetCurrentThreadId() == threadId);
  for (;;) {
    LARGE_INTEGER frequency;
    LARGE_INTEGER ticks;
    QueryPerformanceCounter(&ticks);
    QueryPerformanceFrequency(&frequency);
    uint64_t currentTime = ticks.QuadPart / (frequency.QuadPart / 1000);
    auto timerContextPair = timers.begin();
    auto end = timers.end();
    while (timerContextPair != end && timerContextPair->first <= currentTime) {
      resumingContexts.push(timerContextPair->second);
      timerContextPair = timers.erase(timerContextPair);
    }

    OVERLAPPED_ENTRY entries[16];
    ULONG actual = 0;
    if (GetQueuedCompletionStatusEx(completionPort, entries, 16, &actual, 0, TRUE) == TRUE) {
      assert(actual > 0);
      for (ULONG i = 0; i < actual; ++i) {
        if (entries[i].lpOverlapped == reinterpret_cast<LPOVERLAPPED>(remoteSpawnOverlapped)) {
          EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection));
          assert(remoteNotificationSent);
          assert(!remoteSpawningProcedures.empty());
          do {
            spawn(std::move(remoteSpawningProcedures.front()));
            remoteSpawningProcedures.pop();
          } while (!remoteSpawningProcedures.empty());

          remoteNotificationSent = false;
          LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection));
          continue;
        }

        void* context = reinterpret_cast<DispatcherContext*>(entries[i].lpOverlapped)->context;
        resumingContexts.push(context);
      }
    } else {
      DWORD lastError = GetLastError();
      if (lastError == WAIT_TIMEOUT) {
        break;
      } else if (lastError != WAIT_IO_COMPLETION) {
        throw std::runtime_error("Dispatcher::dispatch, GetQueuedCompletionStatusEx failed, result=" + std::to_string(lastError));
      }
    }
  }

  if (!resumingContexts.empty()) {
    resumingContexts.push(GetCurrentFiber());
    dispatch();
  }
}
Ejemplo n.º 18
0
 SafeThreadToFibre (LPVOID &fiber)
     :m_converted(false)
     ,m_fiber(fiber)
 {
     fiber = GetCurrentFiber ();
     if ((fiber == 0) || (fiber == (LPVOID)0x1E00/*see boost*/))
     {
         fiber = ConvertThreadToFiber (NULL);
         if (!fiber)
             throw 0;
         m_converted = true;
     }
 }
Ejemplo n.º 19
0
void
coro_transfer (coro_context *prev, coro_context *next)
{
  if (!prev->fiber)
    {
      prev->fiber = GetCurrentFiber ();

      if (prev->fiber == 0 || prev->fiber == (void *)0x1e00)
        prev->fiber = ConvertThreadToFiber (0);
    }

  SwitchToFiber (next->fiber);
}
Ejemplo n.º 20
0
void TaskScheduler::WaitForCounter(std::shared_ptr<AtomicCounter> &counter, int value) {
	if (counter->load() == value) {
		return;
	}

	// Switch to a new Fiber
	m_fiberPool.wait_dequeue(tls_fiberToSwitchTo);

	tls_currentFiber = GetCurrentFiber();
	tls_waitingCounter = counter.get();
	tls_waitingValue = value;
	
	SwitchToFiber(m_counterWaitingFibers[tls_threadId]);
}
Ejemplo n.º 21
0
Dispatcher::Dispatcher() {
  static_assert(sizeof(CRITICAL_SECTION) == sizeof(Dispatcher::criticalSection), "CRITICAL_SECTION size doesn't fit sizeof(Dispatcher::criticalSection)");
  BOOL result = InitializeCriticalSectionAndSpinCount(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection), 4000);
  assert(result != FALSE);
  std::string message;
  if (ConvertThreadToFiberEx(NULL, 0) == NULL) {
    message = "ConvertThreadToFiberEx failed, " + lastErrorMessage();
  } else {
    completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
    if (completionPort == NULL) {
      message = "CreateIoCompletionPort failed, " + lastErrorMessage();
    } else {
      WSADATA wsaData;
      int wsaResult = WSAStartup(0x0202, &wsaData);
      if (wsaResult != 0) {
        message = "WSAStartup failed, " + errorMessage(wsaResult);
      } else {
        remoteNotificationSent = false;
        reinterpret_cast<LPOVERLAPPED>(remoteSpawnOverlapped)->hEvent = NULL;
        threadId = GetCurrentThreadId();

        mainContext.fiber = GetCurrentFiber();
        mainContext.interrupted = false;
        mainContext.group = &contextGroup;
        mainContext.groupPrev = nullptr;
        mainContext.groupNext = nullptr;
        mainContext.inExecutionQueue = false;
        contextGroup.firstContext = nullptr;
        contextGroup.lastContext = nullptr;
        contextGroup.firstWaiter = nullptr;
        contextGroup.lastWaiter = nullptr;
        currentContext = &mainContext;
        firstResumingContext = nullptr;
        firstReusableContext = nullptr;
        runningContextCount = 0;
        return;
      }

      BOOL result2 = CloseHandle(completionPort);
      assert(result2 == TRUE);
    }

    BOOL result2 = ConvertFiberToThread();
    assert(result == TRUE);
  }
  
  DeleteCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection));
  throw std::runtime_error("Dispatcher::Dispatcher, " + message);
}
Ejemplo n.º 22
0
        void FiberManager::YieldFiber()
        {
            const auto fiber = GetCurrentFiber();
            ASSERT(fiber != nullptr);

            const auto threadIndex = fiber->m_threadIndex;
            ASSERT(threadIndex >= 0 && threadIndex < int(m_threadData.size()));
            auto&& threadData = m_threadData[threadIndex];

#if defined (WINDOWS)
            SwitchToFiber(threadData.m_mainFiber);
#else
            static_assert(false, "implement this function for this OS");
#endif
        }
Ejemplo n.º 23
0
void ScriptMainSetup()
{
	sGameReloaded = true;
	sMainFib = GetCurrentFiber();

	if (sScriptFib == nullptr)
	{
		// Create our own fiber for the common language runtime once
		sScriptFib = CreateFiber(0, reinterpret_cast<LPFIBER_START_ROUTINE>(&ScriptMainLoop), nullptr);
	}

	while (true)
	{
		// Yield execution
		scriptWait(0);

		// Switch to our own fiber and wait for it to switch back
		SwitchToFiber(sScriptFib);
	}
}
Ejemplo n.º 24
0
        void FiberManager::YieldFiberToService(FiberService* service, void* requestData)
        {
            const auto fiber = GetCurrentFiber();
            ASSERT(fiber != nullptr);

            const auto threadIndex = fiber->m_threadIndex;
            ASSERT(threadIndex >= 0 && threadIndex < int(m_threadData.size()));
            auto&& threadData = m_threadData[threadIndex];

            // we set this before pushing the service fiber so it has all the data it needs to begin
            ASSERT(fiber->m_serviceData == nullptr);
            fiber->m_serviceData = requestData;
            service->PushServiceFiber(fiber);

#if defined (WINDOWS)
            SwitchToFiber(threadData.m_mainFiber);
#else
            static_assert(false, "implement this function for this OS");
#endif
        }
Ejemplo n.º 25
0
int pthread_np_convert_self_to_fiber()
{
  pthread_t pth = pthread_self();
  if (!pth)
    return 1;
  if (!pth->fiber) {
    void* fiber = GetCurrentFiber();
    /* Beware: undocumented (but widely used) method below to check if
       the thread is already converted. */
    if (fiber != NULL && fiber != (void*)0x1E00) {
      pth->fiber = fiber;
      pth->own_fiber = 0;
    } else {
      pth->fiber = ConvertThreadToFiber(pth);
      pth->own_fiber = 1;
    }
    if (!pth->fiber)
      return 1;
  }
  return 0;
}
Ejemplo n.º 26
0
/* Thread function for [pthread_create]d threads. Thread may become a
   fiber later, but (as stated above) it isn't supposed to be
   reattached to other system thread, even after it happens.
*/
DWORD WINAPI Thread_Function(LPVOID param)
{
  pthread_t self = (pthread_t) param;

  self->teb = NtCurrentTeb();
  thread_or_fiber_function(param);
  CloseHandle(self->handle);
  {
    void* fiber = self->fiber;
    free(self);
    if (fiber) {
      /* If thread was converted to fiber, deleting the fiber from
         itself exits the thread. There are some rumors on possible
         memory leaks if we just ExitThread or return here, hence the
         statement below. However, no memory leaks on bare ExitThread
         were observed yet. */
      DeleteFiber(GetCurrentFiber());
    }
  }
  return 0;
}
Ejemplo n.º 27
0
int async_fibre_init_dispatcher(async_fibre *fibre)
{
    LPVOID dispatcher;

    dispatcher = (LPVOID)TlsGetValue(asyncwindispatch);
    if (dispatcher == NULL) {
        fibre->fibre = ConvertThreadToFiber(NULL);
        if (fibre->fibre == NULL) {
            fibre->converted = 0;
            fibre->fibre = GetCurrentFiber();
            if (fibre->fibre == NULL)
                return 0;
        } else {
            fibre->converted = 1;
        }
        if (TlsSetValue(asyncwindispatch, (LPVOID)fibre->fibre) == 0)
            return 0;
    } else {
        fibre->fibre = dispatcher;
    }
    return 1;
}
Ejemplo n.º 28
0
VOID WINAPI LogMessage(PVOID pFlsValue)
{
   TCHAR szMsg[MAX_PATH];

   // Check if we are in a fiber because this function can be called 
   // outside a fiber execution
   if (IsThreadAFiber())
   {
      PVOID pFiberData = GetCurrentFiber();
      PCTSTR pszFlsValue = (PCTSTR)FlsGetValue(g_dwSlot);
      StringCchPrintf(szMsg, _countof(szMsg), TEXT("[0x%x - %s] %s\n"), 
         pFiberData,
         (pszFlsValue == NULL) ? TEXT("'Null value'") : (PCTSTR)pszFlsValue,
         (pFlsValue == NULL) ? TEXT("'Null value'") : (PCTSTR)pFlsValue);
   }
   else
   {
      StringCchCopy(szMsg, _countof(szMsg), TEXT("No more a fiber...\n"));
   }
   /* Sends a string to the debugger for display. */
   OutputDebugString(szMsg);
}
sc_cor_pkg_fiber::sc_cor_pkg_fiber( sc_simcontext* simc )
: sc_cor_pkg( simc )
{
    if( ++ instance_count == 1 ) {
        // initialize the main coroutine
        assert( main_cor.m_fiber == 0 );
        main_cor.m_fiber = ConvertThreadToFiber( 0 );

        if( !main_cor.m_fiber && GetLastError() == ERROR_ALREADY_FIBER ) {
            // conversion of current thread to fiber has failed, because
            // someone else already converted the main thread to a fiber
            // -> store current fiber
            main_cor.m_fiber = GetCurrentFiber();
        }
        assert( main_cor.m_fiber != 0 );

#       if defined(__GNUC__) && __USING_SJLJ_EXCEPTIONS__
            // initialize the current coroutine
            assert( curr_cor == 0 );
            curr_cor = &main_cor;
#       endif
    }
}
Ejemplo n.º 30
0
void Coro_StartWithArg(CallbackBlock *block)
{
#ifdef USE_FIBERS
	MEMORY_BASIC_INFORMATION meminfo;
	if (block->associatedCoro->fiber != GetCurrentFiber())
		abort();
	// Set the start of the stack for future comparaison. According to
	// http://msdn.microsoft.com/en-us/library/ms686774(VS.85).aspx,
	// some part of the stack is reserved for running an handler if
	// the fiber exhaust its stack, but we have no way of retrieving
	// this information (SetThreadStackGuarantee() is not supported
	// on WindowsXP), so we have to assume that it is the default
	// 64kB.
	// Look at the descriptors of the meminfo structure, which is
	// conveniently located on the stack we are interested into.
	VirtualQuery(&meminfo, &meminfo, sizeof meminfo);
	block->associatedCoro->stack =
		(char*)meminfo.AllocationBase + 64 * 1024;
#endif
	(block->func)(block->context);
	printf("Scheduler error: returned from coro start function\n");
	exit(-1);
}