예제 #1
0
파일: Fiber.cpp 프로젝트: yorung/MySnippets
int main(int argc, WCHAR* argv[])
{
	fiberA = CreateFiber(0, (LPFIBER_START_ROUTINE)FiberA, (LPVOID)0);
	fiberB = CreateFiber(0, (LPFIBER_START_ROUTINE)FiberB, (LPVOID)0);
	mainFiber = ConvertThreadToFiber(NULL);
	for (int i = 0; i < 20; i++) {
		SwitchToFiber(fiberA);
		SwitchToFiber(fiberB);
		Sleep(100);
	}
	return 0;
}
예제 #2
0
void RunTimeStep(T* mSys, const int frame) {

	if (frame % 100 == 0 && frame * timestep < 20) {
		for (int i = 0; i < 40; i++) {
			CreateFiber(mSys, Vector(2 - 1.6 * 0, 3, i / 8.0));
			CreateFiber(mSys, Vector(2 - 1.6 * 1, 3, i / 8.0));
			CreateFiber(mSys, Vector(2 - 1.6 * 2, 3, i / 8.0));
			CreateFiber(mSys, Vector(2 - 1.6 * 3, 3, i / 8.0));
			fibers += 4;
		}
		cout << "Fibers: " << fibers << endl;
	}
}
예제 #3
0
파일: coroutine.cpp 프로젝트: ennis/rift
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());
}
예제 #4
0
TContMachineContext::TContMachineContext(const TContClosure& c)
    : Fiber_(CreateFiber(c.Stack.Len, (LPFIBER_START_ROUTINE)ContextTrampoLine, (LPVOID)c.TrampoLine))
    , MainFiber_(false)
{
    if (!Fiber_) {
        ythrow yexception() << "fiber error";
    }
}
예제 #5
0
inline int setup_coroutine(cothread_ctx* tctx, coroutine* c, size_t ssize)
{
	c->ctx = CreateFiber(ssize, &FiberFunc, tctx);
	if (c->ctx == NULL)
	{
	}
	c->stk_size = ssize;
	return (c->ctx==NULL) ? -1 : 0;
}
예제 #6
0
Coroutine *qemu_coroutine_new(void)
{
    const size_t stack_size = 1 << 20;
    CoroutineWin32 *co;

    co = g_malloc0(sizeof(*co));
    co->fiber = CreateFiber(stack_size, coroutine_trampoline, &co->base);
    return &co->base;
}
예제 #7
0
	INT32 CoCreate(void ** pCoID, coroutine_func pFunc, void * pArg)
	{
		*pCoID = CreateFiber(0, pFunc, pArg);
		if (*pCoID == NULL)
		{
			gErrorStream("create fiber failed.\n");
		}

		return 0;
	}
예제 #8
0
        FiberImpl(const BodyFn &fn, int stackSize) : m_bodyFn(fn), m_fiberToReturn(0)
        {
            ESS_ASSERT(fn);
            if (stackSize <= 0) stackSize = CDefaultStackSize;

            MainThreadInit();

            // create fiber
            m_handle = CreateFiber(stackSize, &FiberImpl::FiberFunc, this);
            ESS_ASSERT(m_handle != 0);
        }
예제 #9
0
struct ff_arch_fiber *ff_arch_fiber_create(ff_arch_fiber_func arch_fiber_func, void *ctx, int stack_size)
{
	struct ff_arch_fiber *fiber;

	ff_assert(stack_size > 0);

	fiber = (struct ff_arch_fiber *) ff_malloc(sizeof(*fiber));
	fiber->handle = CreateFiber(stack_size, (LPFIBER_START_ROUTINE) arch_fiber_func, ctx);
	ff_winapi_fatal_error_check(fiber->handle != NULL, L"cannot create new fiber");
	return fiber;
}
예제 #10
0
파일: coro.c 프로젝트: AlwaysGeeky/nanogui
void
coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize)
{
  ctx->fiber = 0;
  ctx->coro  = coro;
  ctx->arg   = arg;

  if (!coro)
    return;

  ctx->fiber = CreateFiber (ssize, coro_init, ctx);
}
예제 #11
0
	uthread_impl *uthread_create(uthread::uthread_start_t _start, void *_param)
	{
		uthread_impl *cur = ::netlib::current();
		handle<uthread_impl> thr = new uthread_impl(_start, _param);

		// 1 <-- creates the smallest possible stack, it can grow, worry not.
		void *fib = CreateFiber(1, (LPFIBER_START_ROUTINE)&uthread_fiber_start, thr.get());
		if(!fib)
			return NULL;

		thr->fiber = fib;
		return thr.get();
	}
예제 #12
0
static inline void load_context(const void* addr)
{
    struct regs *context = (struct regs*)addr;
    if (UNLIKELY(context->start))
    {   /* need setup before switching to it */
        context->uc = CreateFiber(context->stack_size,
                        (LPFIBER_START_ROUTINE)start_thread, context->start);
        /* can't assign stack pointer, only stack size */
        context->stack_size = 0;
        context->start = NULL;
    }
    SwitchToFiber(context->uc);
}
예제 #13
0
파일: fiber.cpp 프로젝트: rod-lin/ink
int InkCoro_Scheduler::create(InkCoro_Function fp, void *arg)
{
	InkCoro_Routine *co = new InkCoro_Routine();

	co->fib = CreateFiber(0, (LPFIBER_START_ROUTINE)wrapper,
						  co->tmp_arg = new InkCoro_Scheduler_wrapper_arg(this, co));
	co->func = fp;
	co->arg = arg;

	pool.push_back(co);

	return 0;
}
예제 #14
0
int main(int argc, const char* argv[])
{
	InitCommonControls();

	if (AttachConsole(ATTACH_PARENT_PROCESS))
	{
		freopen("CONOUT$", "wb", stdout);
		freopen("CONOUT$", "wb", stderr);
	}

	uifiber = ConvertThreadToFiber(NULL);
	assert(uifiber);

	appfiber = CreateFiber(0, application_cb, NULL);
	assert(appfiber);

	realargc = argc;
	realargv = argv;

	/* Run the application fiber. This will deschedule when it wants an
	 * event.
	 */

	SwitchToFiber(appfiber);

	/* And now the event loop. */

	int oldtimeout = -1;
	for (;;)
	{
		MSG msg;

		dpy_flushkeys();

		if (timeout != oldtimeout)
		{
			if (timeout == -1)
				KillTimer(window, TIMEOUT_TIMER_ID);
			else
				SetTimer(window, TIMEOUT_TIMER_ID, timeout*1000, NULL);
			oldtimeout = timeout;
		}

		GetMessageW(&msg, NULL, 0, 0);

		if (DispatchMessageW(&msg) == 0)
			TranslateMessage(&msg);
	}

	return 0;
}
예제 #15
0
        bool Fiber::Init(int threadIndex, unsigned stackSize, FiberPool* ownerPool)
        {
            if (m_threadIndex >= 0)
                return false;
            m_threadIndex = threadIndex;

#if defined(WINDOWS)
            m_fiber = CreateFiber(stackSize, &FiberMain, this);
#endif
            m_ownerPool = ownerPool;
            if (m_fiber == false)
                return false;
            return true;
        }
예제 #16
0
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
    // Reset data
    i = 0;
    memset( buffer, 0, sizeof(buffer) );

    // Convert this thread
    g_pFibers[FIBER_PRIMARY] = ConvertThreadToFiber( NULL );

    // Create the fibers
    g_pFibers[FIBER1] = CreateFiber( 0, Fiber1, NULL );
    g_pFibers[FIBER2] = CreateFiber( 0, Fiber2, NULL );

    // Execute the fibers
    SwitchToFiber( g_pFibers[FIBER1] );

    // Terminate the input
    buffer[i++] = '\0';

    DeleteFiber( g_pFibers[FIBER1] );
    DeleteFiber( g_pFibers[FIBER2] );

    OutputDebugString( buffer );
}
예제 #17
0
int coroutine_init(struct coroutine *co)
{
	if (leader.fiber == NULL) {
		leader.fiber = ConvertThreadToFiber(&leader);
		if (leader.fiber == NULL)
			return -1;
	}

	co->fiber = CreateFiber(0, &coroutine_trampoline, co);
	co->ret = 0;
	if (co->fiber == NULL)
		return -1;

	return 0;
}
예제 #18
0
/*
 * implementation for context_call
 */
void *  context_call(sc_context *  pContext,
                     pcontext_call_routine f,
                     void *  prm) {

  assert(pContext != NULL);
  assert(f        != NULL);

  if (pContext->pFiber != NULL) context_complete(pContext);
  pContext->pRoutine      = f;
  pContext->pParameter    = (void **)malloc(sizeof(void *));
  *(pContext->pParameter) = prm;
  pContext->pParent       = current_context;
  pContext->state         = FS_PREPARED;
  pContext->pFiber        = CreateFiber(pContext->stack_size, fp, pContext);
  return context_recall(pContext);
}
예제 #19
0
파일: Coro.c 프로젝트: doublec/io
void Coro_setup(Coro *self, void *arg)
{
	// If this coro was recycled and already has a fiber, delete it.
	// Don't delete the main fiber. We don't want to commit suicide.

	if (self->fiber && !self->isMain)
	{
		DeleteFiber(self->fiber);
	}

	self->fiber = CreateFiber(Coro_stackSize(self),
							  (LPFIBER_START_ROUTINE)Coro_StartWithArg,
							 (LPVOID)arg);
	if (!self->fiber) {
		DWORD err = GetLastError();
		exit(err);
	}
}
예제 #20
0
/* LWP_CreateProcess - create a new fiber and start executing it.
 *
 * Arguments:
 *	funP - start function
 *	stacksize - size of 
 *	priority - LWP priority
 *	argP - initial parameter for start function
 *	name - name of LWP
 *
 * Return:
 *	pid - handle of created LWP
 *	value:
 *	0 - success
 *	LWP_EINIT - error in intialization.
 *
 */
int LWP_CreateProcess(int (*funP)(), int stacksize, int priority, void *argP,
		      char *name, PROCESS *pid)
{
    PROCESS pcb;
    
    purge_dead_pcbs();

    pcb = (PROCESS)malloc(sizeof(*pcb));
    if (pcb == NULL)
	return LWP_ENOMEM;
    (void) memset((void*)pcb, 0, sizeof(*pcb));

    /*
     * on some systems (e.g. hpux), a minimum usable stack size has
     * been discovered
     */
    if (stacksize < lwp_MinStackSize) {
      stacksize = lwp_MinStackSize;
    }
    /* more stack size computations; keep track of for IOMGR */
    if (lwp_MaxStackSeen < stacksize)
	lwp_MaxStackSeen = stacksize;

    pcb->fiber = CreateFiber(stacksize, Enter_LWP, pcb);
    if (pcb->fiber == NULL) {
	free((void*)pcb);
	return LWP_EINIT;
    }
    Debug(0, ("Create: pcb=0x%p, funP=0x%p, argP=0x%p\n", pcb, funP, argP))
    /* Fiber is now created, so fill in PCB */
    Initialize_PCB(pcb, priority, stacksize, funP, argP, name);
    Debug(10, ("Create: Insert 0x%p into runnable at priority %d\n", pcb, priority))
    insert(pcb, &runnable[priority]);

    LWPANCHOR.processcnt++;

    /* And hand off execution. */
    SwitchToFiber(pcb->fiber);

    *pid = pcb;

    return LWP_SUCCESS;
}
예제 #21
0
/* Create thread or fiber, depending on current thread's "fiber
   factory mode". In the latter case, switch into newly-created fiber
   immediately.
*/
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg)
{
  pthread_t pth = (pthread_t)calloc(sizeof(pthread_thread),1);
  pthread_t self = pthread_self();
  int i;
  HANDLE createdThread = NULL;

  if (self && self->fiber_factory) {
    pth->fiber = CreateFiber (attr ? attr->stack_size : 0, Fiber_Function, pth);
    if (!pth->fiber) return 1;
    pth->created_as_fiber = 1;
    /* Has no fiber-group until someone enters it (we will) */
  } else {
    createdThread = CreateThread(NULL, attr ? attr->stack_size : 0,
                                 Thread_Function, pth, CREATE_SUSPENDED, NULL);
    if (!createdThread) return 1;
    /* FCAT is its own fiber-group [initially] */
    pth->fiber_group = pth;
    pth->handle = createdThread;
  }
  pth->start_routine = start_routine;
  pth->arg = arg;
  if (self) {
    pth->blocked_signal_set = self->blocked_signal_set;
  } else {
    sigemptyset(&pth->blocked_signal_set);
  }
  pth->state = pthread_state_running;
  pthread_mutex_init(&pth->lock, NULL);
  pthread_mutex_init(&pth->fiber_lock, NULL);
  pthread_cond_init(&pth->cond, NULL);
  pth->detached = 0;
  if (thread) *thread = pth;
  if (pth->fiber) {
    pthread_np_switch_to_fiber(pth);
  } else {
    /* Resume will unlock, so we lock here */
    pthread_mutex_lock(&pth->fiber_lock);
    pthread_np_resume(pth);
  }
  return 0;
}
예제 #22
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);
	}
}
예제 #23
0
void
_PR_MD_INIT_CONTEXT(PRThread *thread, char *top, void (*start) (void), PRBool *status)
{
    thread->md.fiber_fn = (void (*)(void *))start;
    thread->md.fiber_id = CreateFiber(thread->md.fiber_stacksize, 
        (LPFIBER_START_ROUTINE)_pr_fiber_mainline, NULL);
    if (thread->md.fiber_id != 0)
        *status = PR_TRUE;
    else {
        DWORD oserror = GetLastError();
        PRErrorCode prerror;
        if (oserror == ERROR_NOT_ENOUGH_MEMORY) {
            prerror = PR_OUT_OF_MEMORY_ERROR;
        } else {
            prerror = PR_UNKNOWN_ERROR;
        }
        PR_SetError(prerror, oserror);
        *status = PR_FALSE;
    }
}
예제 #24
0
/*--------------------------------------------------------------------------*/
void
mtarch_start(struct mtarch_thread *thread,
	     void (* function)(void *data),
	     void *data)
{
#if defined(_WIN32) || defined(__CYGWIN__)

  thread->mt_thread = CreateFiber(0, (LPFIBER_START_ROUTINE)function, data);

#else /* _WIN32 || __CYGWIN__ */

  thread->mt_thread = malloc(sizeof(struct mtarch_t));

  getcontext(&((struct mtarch_t *)thread->mt_thread)->context);

  ((struct mtarch_t *)thread->mt_thread)->context.uc_link = NULL;
  ((struct mtarch_t *)thread->mt_thread)->context.uc_stack.ss_sp = 
			((struct mtarch_t *)thread->mt_thread)->stack;
  ((struct mtarch_t *)thread->mt_thread)->context.uc_stack.ss_size = 
			sizeof(((struct mtarch_t *)thread->mt_thread)->stack);

  /* Some notes:
     - If a CPU needs stronger alignment for the stack than malloc()
       guarantees (like i.e. IA64) then makecontext() is supposed to
       add that alignment internally.
     - According to POSIX the arguments to function() are of type int
       and there are in fact 64-bit implementations which support only
       32 bits per argument meaning that a pointer argument has to be
       splitted into two arguments.
     - Most implementations interpret context.uc_stack.ss_sp on entry
       as the lowest stack address even if the CPU stack actually grows
       downwards. Although this means that ss_sp does NOT represent the
       CPU stack pointer this behaviour makes perfectly sense as it is
       the only way to stay independent from the CPU architecture. But
       Solaris prior to release 10 interprets ss_sp as highest stack
       address thus requiring special handling. */
  makecontext(&((struct mtarch_t *)thread->mt_thread)->context,
	      (void (*)(void))function, 1, data);

#endif /* _WIN32 || __CYGWIN__ */
}
예제 #25
0
파일: coroutine.c 프로젝트: Strongc/EffiLib
void coroutine_resume(struct schedule * S, int id) 
{
    //         assert(S->running == -1);
    //         assert(id >=0 && id < S->cap);
    struct coroutine *C = S->co[id];
    int status;
    if (C == NULL)
        return;
    status = C->status;
    switch(status) {
    case COROUTINE_READY:
        C->ctx = CreateFiber(0, fiberProc, (void*)S);
    case COROUTINE_SUSPEND:
        S->running = id;
        C->status = COROUTINE_RUNNING;
        SwitchToFiber(C->ctx);
        break;
    default:
        assert(0);
    }
}
예제 #26
0
__declspec(dllexport) handle_t __stdcall createC64 ()
{
    handle_t handle = 0;

    try
    {
        std::auto_ptr<Acid64> inst(new Acid64);
        inst->engine = ISidplay2::create ();
        if (!inst->engine)
            throw 0;
        inst->cycleCorrection = 0;
        inst->cpuClock = 0.0;
        inst->builder.create (inst->engine->info().maxsids);

        // Create the fiber
        inst->engineFiber = CreateFiber (0, &start, inst.get());
        if (!inst->engineFiber)
            throw 0;

        try
        {
            SafeThreadToFibre convert(inst->mainFiber);
            SwitchToFiber (inst->engineFiber);
        }
        catch (...)
        {
            DeleteFiber (inst->engineFiber);
            throw;
        }

        handle = (handle_t)inst.get ();
        inst.release ();
    }
    catch (...)
    {
        ;
    }

    return handle;
}
예제 #27
0
파일: Fiber.cpp 프로젝트: Rn86/Boron
		Impl(FiberUID uid, const FiberCallback & callback, size_t szStack)
			: Impl(uid, CreateFiber(szStack, (LPFIBER_START_ROUTINE)FiberDispatcher::Dispatch, new FiberDispatcher(callback)))
		{
		}
예제 #28
0
void jsInit()
{
#ifdef DEBUG_OUTPUT
	g_pDebugLog = fopen("JS_DEBUG.log", "w");
#endif 

	//find number of cores
	SYSTEM_INFO sysInfo = { 0 };
	GetSystemInfo(&sysInfo);
	g_numProcessors = sysInfo.dwNumberOfProcessors;


	//spawn fibers
	for (int i = 0; i < NUM_FIBERS; ++i)
	{
		g_fibers[i].fiber = CreateFiber(FIBER_STACK_SIZE, fiberRoutine, g_fibers + i);
		g_fibers[i].pNextInWaitList = NULL;
		g_fibers[i].status = UNUSED;
		g_pFiberPool[NUM_FIBERS - 1 - i] = g_fibers + i;
	}


	//init waiting fibers
	memset(g_waitingFibers, 0, sizeof(g_waitingFibers));
	g_waitingFiberHead = 0;
	g_waitListTail.pFiber = NULL;
	g_waitListTail.pNextWaitingFiber = NULL;
	g_waitListTail.time = 0;

	//get performance frequency
	QueryPerformanceFrequency((LARGE_INTEGER*)&g_performanceFrequency);

	//init jobs
	for (int i = 2; i < MAX_JOBS; ++i)
	{
		g_jobs[i - 1].pNextJob = g_jobs + i;
	}
	g_pFreeJob = g_jobs + 1;
	g_pJobQueueHead = g_jobs;
	g_dummyJob.threadId = 0x0;
	g_dummyJob.pNextJob = g_pJobQueueHead;
	g_dummyJob.pName = "__dummy";

	//spawn threads
	g_threadData = TlsAlloc();

	for (int i = 0; i < g_numProcessors; ++i)
	{
		//create thread
		if (i == 0)
		{
			g_threads[0].handle = GetCurrentThread();
		}
		else
		{
			g_threads[i].handle = CreateThread(NULL, 0, threadStart, g_threads + i, 0, NULL);
		}

		g_threads[i].id = 0x1 << i;
		g_threads[i].ppJobQueueTail = &(g_dummyJob.pNextJob);



		//lock thread to specific cpu
		SetThreadAffinityMask(g_threads[i].handle, 1 << i);
	}
	TlsSetValue(g_threadData, g_threads + 0);

	initCounterAllocator();

#ifdef DEBUG_OUTPUT
	fprintf(g_pDebugLog, "%lld \t jobsystem started\n", time(NULL));
#endif

}
예제 #29
0
Fiber::Fiber() {
	m_fiber = CreateFiber(0, Fiber::fiberStartingFunction, this);
	m_isThread = false;
}
예제 #30
0
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {

   // Counter fiber execution context
   PVOID pFiberCounter = NULL;   

   // Convert this thread to a fiber.

   /* Converts the current thread into a fiber. 
    * You must convert a thread into a fiber 
	* before you can schedule other fibers. */
   g_FiberInfo.pFiberUI = ConvertThreadToFiber(NULL);

   /* Allocates a fiber local storage (FLS) index. 
    * Any fiber in the process can subsequently use this index 
	* to store and retrieve values that are local to the fiber. */
   g_dwSlot = FlsAlloc(LogMessage);
   FlsSetValue(g_dwSlot, TEXT("UI fiber"));


   // Create the application's UI window.
   g_FiberInfo.hwnd = CreateDialog(hinstExe, MAKEINTRESOURCE(IDD_COUNTER), 
      NULL, Dlg_Proc);

   // Update the window showing which fiber is executing.
   SetDlgItemText(g_FiberInfo.hwnd, IDC_FIBER, TEXT("User interface"));

   // Initially, there is no background processing to be done.
   g_FiberInfo.bps = BPS_DONE;

   // While the UI window still exists...
   BOOL fQuit = FALSE;
   while (!fQuit) {

      // UI messages are higher priority than background processing.
      MSG msg;
	  /* Dispatches incoming sent messages, checks 
	   * the thread message queue for a posted message, 
	   * and retrieves the message (if any exist). 
	   * PM_REMOVE 0x0001 
	   * Messages are removed from the queue after processing by PeekMessage.
	   */
      if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

         // If a message exists in the queue, process it.
	     /* Determines whether a message is intended 
		  * for the specified dialog box and, 
		  * if it is, processes the message. 
		  * hDlg [in] Type: HWND A handle to the dialog box.
          * lpMsg [in] Type: LPMSG A pointer to an MSG structure 
		  * that contains the message to be checked.
		  */
         if (!IsDialogMessage(g_FiberInfo.hwnd, &msg)) 
		 {
			 /* Translates virtual-key messages into character messages. 
			  * The character messages are posted to the calling thread's message queue, 
			  * to be read the next time the thread calls the GetMessage or PeekMessage function */
             TranslateMessage(&msg);
			 /* Dispatches a message to a window procedure. 
			  * It is typically used to dispatch a message retrieved by the GetMessage function. */
             DispatchMessage(&msg);
         }

         fQuit = (msg.message == WM_QUIT);
         
         if (fQuit)
         {
            // Release FLS slot
            FlsFree(g_dwSlot);

            // The background processing must be stopped. 
            if (pFiberCounter != NULL) { 
               // A recalculation fiber exists; delete it
               DeleteFiber(pFiberCounter); 
               pFiberCounter = NULL; 
            }
         
            // Quit the fiber mode and return to simple thread mode
            ConvertFiberToThread();
            g_FiberInfo.pFiberUI = NULL;
         }
         
      } else {

         // No UI msgs exist; check the state of the background processing.
         switch (g_FiberInfo.bps) {
            case BPS_DONE:
               // No background processing to do; wait for a UI event.
               /* Yields control to other threads when a thread has no other messages 
			    * in its message queue. 
				* The WaitMessage function suspends the thread 
				* and does not return until a new message 
				* is placed in the thread's message queue. */
               WaitMessage();
               break;

            case BPS_STARTOVER:
               // User changed the count; 
               // cancel the current background processing.
               if (pFiberCounter != NULL) { 
                  // A recalculation fiber exists; delete it so that
                  // background processing starts over from the beginning.
                  DeleteFiber(pFiberCounter); 
                  pFiberCounter = NULL; 
               }

               // Convert this thread to a fiber if needed.
               if (g_FiberInfo.pFiberUI == NULL)
                  g_FiberInfo.pFiberUI = ConvertThreadToFiber(NULL);

               LogMessage(TEXT("convert UI thread to fiber..."));

               // Create a new recalc fiber that starts from the beginning.
               pFiberCounter = CreateFiber(0, FiberFunc, &g_FiberInfo);

               // The background processing started; it should continue.
               g_FiberInfo.bps = BPS_CONTINUE;

               // Fall through to BPS_CONTINUE case...

            case BPS_CONTINUE:
               // Allow the background processing to execute...
               SwitchToFiber(pFiberCounter);

               // The background processing has been paused 
               // (because a UI message showed up) or has been 
               // stopped (because the counting has completed).

               // Update the window showing which fiber is executing.
               SetDlgItemText(g_FiberInfo.hwnd, IDC_FIBER, 
                  TEXT("User interface"));

               if (g_FiberInfo.bps == BPS_DONE) { 
                  // The background processing ran to completion. Delete the
                  // fiber so that processing will restart next time.
                  DeleteFiber(pFiberCounter); 
                  pFiberCounter = NULL; 
               
                  // Quit the fiber mode and return to simple thread mode
                  ConvertFiberToThread();
                  g_FiberInfo.pFiberUI = NULL;
               }
               break;
         }  // switch on background processing state

      }  // No UI messages exist
   }  // while the window still exists

   DestroyWindow(g_FiberInfo.hwnd); 

   return(0);  // End the application.
}