void c_ExternalThreadEventWaitHandle::sweep() {
  assert(getState() == STATE_WAITING);

  if (m_event->cancel()) {
    // canceled; the processing thread will take care of cleanup
    return;
  }

  // event has finished, but process() was not called yet
  auto queue = AsioSession::Get()->getExternalThreadEventQueue();
  bool done = queue->hasReceived() && queue->abandonAllReceived(this);
  while (!done) {
    queue->receiveSome();
    done = queue->abandonAllReceived(this);
  }
}
Ejemplo n.º 2
0
void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) {
  assert(wait_handle);
  assert(wait_handle->getContext() == this);

  auto session = AsioSession::Get();
  auto ete_queue = session->getExternalThreadEventQueue();
  auto& sleep_queue = session->getSleepEventQueue();

  if (!session->hasAbruptInterruptException()) {
    session->initAbruptInterruptException();
  }

  while (!wait_handle->isFinished()) {
    // Run queue of ready async functions once.
    if (!m_runnableQueue.empty()) {
      auto current = m_runnableQueue.back();
      m_runnableQueue.pop_back();
      current->resume();
      continue;
    }

    // Process all sleep handles that have completed their sleep.
    if (session->processSleepEvents()) {
      continue;
    }

    // Process all external thread events that have completed their operation.
    // Queue may contain received unprocessed events from failed runUntil().
    if (UNLIKELY(ete_queue->hasReceived()) || ete_queue->tryReceiveSome()) {
      ete_queue->processAllReceived();
      continue;
    }

    // Run default priority queue once.
    if (runSingle(m_priorityQueueDefault)) {
      continue;
    }

    // Wait for pending external thread events...
    if (!m_externalThreadEvents.empty()) {
      // ...but only until the next sleeper (from any context) finishes.
      AsioSession::TimePoint waketime;
      if (sleep_queue.empty()) {
        waketime = AsioSession::getLatestWakeTime();
      } else {
        waketime = sleep_queue.top()->getWakeTime();
      }

      // Wait if necessary.
      if (LIKELY(!ete_queue->hasReceived())) {
        onIOWaitEnter(session);
        ete_queue->receiveSomeUntil(waketime);
        onIOWaitExit(session);
      }

      if (ete_queue->hasReceived()) {
        // Either we didn't have to wait, or we waited but no sleeper timed us
        // out, so just handle the ETEs.
        ete_queue->processAllReceived();
      } else {
        // No received events means the next-to-wake sleeper timed us out.
        session->processSleepEvents();
      }

      continue;
    }

    // If we're here, then the only things left are sleepers.  Wait for one to
    // be ready (in any context).
    if (!m_sleepEvents.empty()) {
      onIOWaitEnter(session);
      std::this_thread::sleep_until(sleep_queue.top()->getWakeTime());
      onIOWaitExit(session);

      session->processSleepEvents();
      continue;
    }

    // Run no-pending-io priority queue once.
    if (runSingle(m_priorityQueueNoPendingIO)) {
      continue;
    }

    // What? The wait handle did not finish? We know it is part of the current
    // context and since there is nothing else to run, it cannot be in RUNNING
    // or SCHEDULED state. So it must be BLOCKED on something. Apparently, the
    // same logic can be used recursively on the something, so there is an
    // infinite chain of blocked wait handles. But our memory is not infinite.
    // What could it possibly mean? I think we are in a deep sh^H^Hcycle.
    // But we can't, the cycles are detected and avoided at blockOn() time.
    // So, looks like it's not cycle, but the word I started typing first.
    assert(false);
    throw FatalErrorException(
      "Invariant violation: queues are empty, but wait handle did not finish");
  }
}
Ejemplo n.º 3
0
void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) {
  assert(!m_current);
  assert(wait_handle);
  assert(wait_handle->getContext() == this);

  auto session = AsioSession::Get();
  uint8_t check_ete_counter = 0;

  if (!session->hasAbruptInterruptException()) {
    session->initAbruptInterruptException();
  }

  while (!wait_handle->isFinished()) {
    // process ready external thread events once per 256 other events
    // (when 8-bit check_ete_counter overflows)
    if (!++check_ete_counter) {
      // queue may contain received unprocessed events from failed runUntil()
      auto queue = session->getExternalThreadEventQueue();
      if (UNLIKELY(queue->hasReceived()) || queue->tryReceiveSome()) {
        queue->processAllReceived();
      }
    }

    // run queue of ready continuations once
    if (!m_runnableQueue.empty()) {
      auto current = m_runnableQueue.front();
      m_runnableQueue.pop();
      m_current = current;
      auto exit_guard = folly::makeGuard([&] {
        m_current = nullptr;
        decRefObj(current);
      });

      m_current->run();
      continue;
    }

    // run default priority queue once
    if (runSingle(m_priorityQueueDefault)) {
      continue;
    }

    // pending external thread events? wait for at least one to become ready
    if (!m_externalThreadEvents.empty()) {
      // queue may contain received unprocessed events from failed runUntil()
      auto queue = session->getExternalThreadEventQueue();
      if (LIKELY(!queue->hasReceived())) {
        // all your wait time are belong to us
        queue->receiveSome();
      }

      queue->processAllReceived();
      continue;
    }

    // run no-pending-io priority queue once
    if (runSingle(m_priorityQueueNoPendingIO)) {
      continue;
    }

    // What? The wait handle did not finish? We know it is part of the current
    // context and since there is nothing else to run, it cannot be in RUNNING
    // or SCHEDULED state. So it must be BLOCKED on something. Apparently, the
    // same logic can be used recursively on the something, so there is an
    // infinite chain of blocked wait handles. But our memory is not infinite.
    // What could it possibly mean? I think we are in a deep sh^H^Hcycle.
    // But we can't, the cycles are detected and avoided at blockOn() time.
    // So, looks like it's not cycle, but the word I started typing first.
    assert(false);
    throw FatalErrorException(
      "Invariant violation: queues are empty, but wait handle did not finish");
  }
}
Ejemplo n.º 4
0
// observation
void NewConditionController::visit_observation(observation *r) {
	static const bool verbose = false;
	if (verbose)
		cout << "REV:" << r->receivers->size() << ": ";
	VecInt hasReceived(proc->nRoles, 0); // flag gets set to true as soon as at least one message is set to this role
	int i = 0;
	for (recipients::const_iterator itr = r->receivers->begin(); itr != r->receivers->end(); ++itr, ++i) {
		//cout << (*itr)->receivers->size() << " ";
		FunctionKey fk = getGroundedProp((*itr)->prop, this->args);
		if (verbose)
			cout << asIntString(fk) << " ";
		for (parameter_symbol_list::const_iterator pitr = (*itr)->receivers->begin(); pitr != (*itr)->receivers->end();
				++pitr) {
			//cout << ":";
			const string& name = (*pitr)->getName();
			if ((*pitr)->isConstant()) {
				if (name == "all") {
					if (verbose)
						cout << "msg " << i << " to all; ";
					hasReceived = VecInt(proc->nRoles, 1);
					for (unsigned k = 0; k < proc->nRoles; k++) {
						ws.obsListByPlyr[k].push_back(fk);
					}
					break;
				} else if (name != "others") { // Message is targeted to a player mentioned as a constant
					// Note that this is independent of args and could be computed in advance
					if (verbose)
						cout << "Msg " << i << " to " << (-1 - r->recipientMapper[name]) << " ("
								<< proc->invObjectTbl["role"][-1 - r->recipientMapper[name]] << ");";
					hasReceived[-1 - r->recipientMapper[name]] = 1;
					ws.obsListByPlyr[-1 - r->recipientMapper[name]].push_back(fk);
				}
			} else { // message is targeted to a player that is bound to a variable
				if (verbose)
					cout << "msg " << i << " to " << args[r->recipientMapper[name]] << " ("
							<< proc->invObjectTbl["role"][args[r->recipientMapper[name]]] << ");";
				hasReceived[args[r->recipientMapper[name]]] = 1;
				ws.obsListByPlyr[args[r->recipientMapper[name]]].push_back(fk);
			}
			//if (name != "all" && name != "others") cout << "Mapping " << name << " to " << r->recipientMapper[name] << "\n";
		}
	}
	i = 0;
	for (recipients::const_iterator itr = r->receivers->begin(); itr != r->receivers->end(); ++itr, ++i) {
		//cout << (*itr)->receivers->size() << " ";
		if ((*itr)->receivers->size() == 1 && (*(*itr)->receivers->begin())->getName() == "others") {
			FunctionKey fk = getGroundedProp((*itr)->prop, this->args);
			if (verbose)
				cout << asIntString(fk) << " ";
			if (verbose)
				cout << "Sending message to OTHERS: ";
			for (unsigned j = 1; j < hasReceived.size(); j++) {
				if (!hasReceived[j]) {
					if (verbose)
						cout << j << " ";
					ws.obsListByPlyr[j].push_back(fk);
				}
			}
			//cout << "\n";
		}
	}
	//cout << "\n";

}