static CALresult waitForKernel(MWCALInfo* ci, CALevent ev, CALuint initialWait, CALint pollingMode)
{
    CALresult err;

    mwMilliSleep(initialWait);  /* Sleep for initial estimate before polling */

    if (pollingMode > 0)
    {
        while (calCtxIsEventDone(ci->calctx, ev) == CAL_RESULT_PENDING)
            mwMilliSleep(pollingMode);
    }
    else if (pollingMode == 0)
    {
        err = mw_calCtxWaitForEvents(ci->calctx, &ev, 1, 0);
        if (err != CAL_RESULT_OK)
        {
            cal_warn("Error waiting for kernel", err);
            return err;
        }
    }
    else /* Busy wait */
    {
        while (calCtxIsEventDone(ci->calctx, ev) == CAL_RESULT_PENDING);
    }

    return CAL_RESULT_OK;
}
/* The function called whenever a normal key is pressed. */
static void specialKeyPressed(int key, int x, int y)
{
    mwMilliSleep(THRASH_SLEEP_INTERVAL);

    switch (key)
    {
        case GLUT_KEY_PAGE_UP:
            scene->z -= DELTAZ;
            scene->changed = TRUE;
            break;
        case GLUT_KEY_PAGE_DOWN:
            scene->z += DELTAZ;
            scene->changed = TRUE;
            break;
        case GLUT_KEY_UP:
            scene->xrot -= DELTAXROT;
            scene->changed = TRUE;
            break;
        case GLUT_KEY_DOWN:
            scene->xrot += DELTAXROT;
            scene->changed = TRUE;
            break;
        case GLUT_KEY_LEFT:
            scene->yrot -= DELTAYROT;
            scene->changed = TRUE;
            break;
        case GLUT_KEY_RIGHT:
            scene->yrot += DELTAYROT;
            scene->changed = TRUE;
            break;
        default:
            break;
    }
}
/* Optionally manually poll for event completion.  This is because some
   versions of both the Nvidia and AMD drivers developed an issue
   where clWaitForEvents/clFinish would cause 100% CPU usage.
*/
cl_int mwCLWaitForEvent(CLInfo* ci, cl_event ev, cl_uint initialWait)
{
    cl_int err;
    cl_int pollingMode = ci->pollingMode;

    if (pollingMode <= MW_POLL_CL_WAIT_FOR_EVENTS)
    {
        return clWaitForEvents(1, &ev);
    }
    else if (pollingMode == MW_POLL_SLEEP_CL_WAIT_FOR_EVENTS)
    {
        err = clFlush(ci->queue);
        if (err != CL_SUCCESS)
            return err;

        mwMilliSleep(initialWait);
        return clWaitForEvents(1, &ev);
    }
    else  /* Manually poll for pollingMode milliseconds */
    {
        cl_int execStatus;

        err = clFlush(ci->queue);  /* Make sure the task is submitted before we wait for it */
        if (err != CL_SUCCESS)
            return err;

        mwMilliSleep(initialWait);

        do
        {
            err = clGetEventInfo(ev,
                                 CL_EVENT_COMMAND_EXECUTION_STATUS,
                                 sizeof(cl_int),
                                 &execStatus,
                                 NULL);
            if (err != CL_SUCCESS)
                return err;

            mwMilliSleep(pollingMode);
        }
        while (execStatus != CL_COMPLETE);

        return CL_SUCCESS;
    }
}
/* In case the main application isn't ready yet, try and wait for a while */
int connectSharedScene()
{
    int tries = 0;

    while (tries < MAX_TRIES)
    {
        if (attemptConnectSharedScene())
        {
            return alreadyAttached(); /* Error if something already attached */
        }

        mwMilliSleep(RETRY_INTERVAL);
        ++tries;
    }

    warn("Could not attach to simulation after %d attempts\n", MAX_TRIES);
    return 1;
}
/* In case the main application isn't ready yet, try and wait for a while */
static scene_t* nbglConnectSharedScene(int instanceId)
{
    int tries = 0;
    scene_t* scene = NULL;

    (void) instanceId;

    while (tries < MAX_TRIES)
    {
        if ((scene = nbglAttemptConnectSharedScene()))
        {
            return scene; /* Error if something already attached */
        }

        mwMilliSleep(RETRY_INTERVAL);
        ++tries;
    }

    mw_printf("Could not attach to simulation after %d attempts\n", MAX_TRIES);
    return NULL;
}
/* The function called whenever a key is pressed. */
static void keyPressed(unsigned char key, int x, int y)
{
    /* avoid thrashing this call */
    mwMilliSleep(THRASH_SLEEP_INTERVAL);

    if (scene->fullscreen)
    {
        mw_finish(EXIT_SUCCESS);
    }

    switch (key)
    {
        case ESCAPE:
        case 'q':
            glutDestroyWindow(window);
            mw_finish(EXIT_SUCCESS);

        case 'h':
            print_bindings(stderr);
            break;

        case 'p':
            scene->paused = !scene->paused;
            break;

        case ' ':
            scene->step = TRUE;
            break;

        case 'b':
            scene->starsize *= 1.1;
            if (scene->starsize > 100.0)
            {
                scene->starsize = 100.0;
            }
            scene->changed = TRUE;
            break;

        case 's':
            scene->starsize *= 0.9;
            if (scene->starsize < 1.0e-3)
            {
                scene->starsize = 1.0e-3;
            }
            scene->changed = TRUE;
            break;

        case 'm':
            scene->ntri *= 2;
            if (scene->ntri > 24)
            {
                scene->ntri = 24;
            }
            scene->changed = TRUE;
            break;

        case 'f':
            scene->ntri /= 2;
            if (scene->ntri < 4)
            {
                scene->ntri = 4;
            }
            scene->changed = TRUE;
            break;

        case 'a':
            scene->drawaxes = !scene->drawaxes;
            scene->changed = TRUE;
            break;
        case '>':
            scene->dt /= 2.0;
            if (scene->dt < 10.0)
            {
                scene->dt = 10.0;
            }
            break;
        case '<':
            scene->dt *= 2.0;
            if (scene->dt > 1.0e6)
            {
                scene->dt = 1.0e6;
            }
            break;

        default:
            break;
    }
}