/**
 * Switch the active activity if there are other activities
 * waiting to run.
 *
 * @param activity The current active activity.
 */
void ActivityManager::relinquish(Activity *activity)
{
    // if we have waiting activities, then let one of them
    // in next.
    if (hasWaiters())
    {
        addWaitingActivity(activity, true);
    }
}
/**
 * Add a waiting activity to the waiting queue.
 *
 * @param waitingAct The activity to queue up.
 * @param release    If true, the kernel lock should be released on completion.
 */
void ActivityManager::addWaitingActivity(RexxActivity *waitingAct, bool release )
{
    ResourceSection lock("ActivityManager::addWaitingActivity", 0);                // need the control block locks
    addWaitingActivityCount += 1;

    // nobody waiting yet?  If the release flag is true, we already have the
    // kernel lock, but nobody is waiting.  In theory, this can't really
    // happen, but we can return immediately if that is true.
    if (waitingActivities.empty())
    {
        // we're done if we already have the lock and the queue is empty.
        if (release)
        {
            return;
        }
        // add to the end
        waitingActivities.push_back(waitingAct);
        // this will ensure this happens before the lock is released
        sentinel = false;
        // we should end up getting the lock immediately, but you never know.
        lock.release();                  // release the lock now
    }
    else
    {
        // add to the end
        waitingActivities.push_back(waitingAct);
        // this will ensure this happens before the lock is released
        sentinel = false;
        // we're going to wait until posted, so make sure the run semaphore is cleared
        waitingAct->clearWait();
        sentinel = true;
        lock.release();                    // release the lock now
        sentinel = false;
        // if we are the current kernel semaphore owner, time to release this
        // so other waiters can
        if (release)
        {
            unlockKernel();
        }
        SysActivity::yield();            // yield the thread
        waitingAct->waitForDispatch();   // wait for this thread to get dispatched again
    }

    sentinel = true;
    lockKernel();                        // get the kernel lock now
    // belt and braces.  it is possible the dispatcher was
    // reentered on the same thread, in which case we have an
    // earlier stack frame waiting on the same semaphore.  Clear it so it
    // get get reposted later.
    waitingAct->clearWait();
    sentinel = false;
    lock.reacquire();                    // get the resource lock back
    sentinel = false;                    // another memory barrier

    // We only get dispatched if we end up at the front of the queue again,
    // so just pop the front element.
    waitingActivities.pop_front();
    sentinel = true;
    // if there's something else in the queue, then post the run semaphore of
    // the head element so that it wakes up next and starts waiting on the
    // run semaphore
    if (hasWaiters())
    {
        waitingActivities.front()->postDispatch();
    }
    // the setting of the sentinel variables acts as a memory barrier to
    // ensure that the assignment of currentActivitiy occurs precisely at this point.
    sentinel = false;
    currentActivity = waitingAct;        /* set new current activity          */
    sentinel = true;
    /* and new active settings           */
    Numerics::setCurrentSettings(waitingAct->getNumericSettings());
}
Exemple #3
0
bool gps_hasWaiters()
   { return hasWaiters(&wait_gps); }