You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
5.7 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
#include "control_chain.H"
#include "parse_control.H"
#include "alarm_manager.H"
#include "controller_events.H"
using namespace std;
using namespace CONTROLLER;
UINT32 CONTROL_CHAIN::global_id = 0;
/// @cond INTERNAL_DOXYGEN
CONTROL_CHAIN::CONTROL_CHAIN(CONTROL_MANAGER* control_mngr, VOID* event_handler, BOOL vector_chain){
_control_mngr = control_mngr;
_name = "";
_wait_for_id = NO_WAIT;
_repeat_token = 1;
_id = global_id;
_event_handler = event_handler;
_block_fire = FALSE;
global_id++;
_vector_chain = vector_chain;
_vector_index = 0;
memset(_repeat,0,sizeof(_repeat));
}
VOID CONTROL_CHAIN::Fire(EVENT_TYPE eventID, CONTEXT* ctx, VOID * ip,
THREADID tid, BOOL bcast, UINT32 alarm_id)
{
// Check if fire is block for this chain
if (_block_fire)
return;
//roll the event to the tool only if it is not a precondition
if (eventID != EVENT_PRECOND){
_control_mngr->Fire(eventID, ctx, ip, tid, bcast,_event_handler, this);
}
// Check if fire is block for this chain before we arm the next event
if (_block_fire)
return;
if (_alarms[alarm_id]->ArmNext()){
ArmNextAlarm(alarm_id, tid, bcast);
}
}
// Late fire event
VOID CONTROL_CHAIN::LateFire(EVENT_TYPE eventID, CONTEXT* ctx, VOID * ip,
THREADID tid, BOOL bcast, UINT32 alarm_id)
{
// Check if fire is block for this chain
if (_block_fire)
return;
_control_mngr->LateFire(eventID, ctx, ip, tid, bcast);
}
VOID CONTROL_CHAIN::Activate(){
//activate the first alarm in the chain only if the chain does not "wait"
if (_wait_for_id == NO_WAIT){
_alarms[0]->Activate();
}
}
VOID CONTROL_CHAIN::ArmChain(UINT32 tid){
_alarms[0]->ArmTID(tid);
}
VOID CONTROL_CHAIN::Arm(UINT32 tid, BOOL bcast, UINT32 alarm_id){
if (bcast || _alarms[alarm_id]->HasGlobalCounter()){
//if we are in broadcast arm all threads in the next alarm
_alarms[alarm_id]->ArmAll();
}
else{
_alarms[alarm_id]->ArmTID(tid);
}
}
VOID CONTROL_CHAIN::Parse(const string& chain_str)
{
vector<string> control_str;
PARSER::SplitArgs(",",chain_str,control_str);
for (UINT32 i=0; i<control_str.size(); i++){
if (PARSER::ConfigToken(control_str[i])){
//parse all the config tokes(repeat,name,waitfor)
PARSER::ParseConfigTokens(control_str[i],this);
}
else {
//generate the alarm
ALARM_MANAGER* alarm_mngr = new ALARM_MANAGER(control_str[i],
this,i,
_control_mngr->HasLateHandler(),
_vector_chain,_vector_index);
_alarms.push_back(alarm_mngr);
}
}
}
BOOL CONTROL_CHAIN::NeedContext(){
return _control_mngr->PassContext();
}
BOOL CONTROL_CHAIN::NeedToRepeat(UINT32 tid){
if (_repeat[tid] < _repeat_token || _repeat_token == REPEAT_INDEFINITELY){
return TRUE;
}
return FALSE;
}
VOID CONTROL_CHAIN::ArmNextAlarm(UINT32 alarm_id, UINT32 tid, BOOL bcast){
UINT32 last_alarm_id = _alarms.size() - 1;
if (alarm_id < last_alarm_id){
//we still have alarm after this one
Arm(tid,bcast,alarm_id+1);
}
else{
//we are in the last alarm check the repeat
_repeat[tid]++;
if (NeedToRepeat(tid)){
Arm(tid,bcast,0);
}
else{
ArmWaitingChains(tid);
}
}
}
VOID CONTROL_CHAIN::SetWaitFor(const string& chain_name){
UINT32 id = _control_mngr->GetChainId(chain_name);
SetWaitFor(id);
}
VOID CONTROL_CHAIN::SetWaitFor(UINT32 chain_id){
CONTROL_CHAIN* chain = _control_mngr->ChainById(chain_id);
if (chain == NULL){
stringstream s;
s << "chain id " << chain_id << " does not exists";
ASSERT(FALSE, s.str());
}
_wait_for_id = chain_id;
chain->AddWaitingChain(this);
}
VOID CONTROL_CHAIN::AddWaitingChain(CONTROL_CHAIN* chain){
_waiting_chains.push_back(chain);
}
VOID CONTROL_CHAIN::ArmWaitingChains(UINT32 tid){
list<CONTROL_CHAIN*>::iterator iter = _waiting_chains.begin();
for(; iter != _waiting_chains.end(); iter++){
CONTROL_CHAIN* chain = *iter;
chain->ArmChain(tid);
}
}
//print debug massages - only when the debug knob is used
VOID CONTROL_CHAIN::DebugPrint(){
for (UINT32 i = 0; i < _alarms.size(); i++){
_alarms[i]->Print();
}
cerr << "REPEAT: " << _repeat_token << endl;
cerr << "NAME: " << _name << endl;
cerr << "WAIT FOR: " << _wait_for_id << endl;
}
BOOL CONTROL_CHAIN::HasStartEvent(){
for (UINT32 i = 0; i < _alarms.size(); i++){
if (_alarms[i]->HasStartEvent()){
return TRUE;
}
}
return FALSE;
}
VOID CONTROL_CHAIN::SetUniformAlarm(ALARM_MANAGER* uniform_alarm){
if (_control_mngr->_uniform_alarm){
ASSERT(FALSE,"Only one uniform control is allowed");
}
_control_mngr->_uniform_alarm = uniform_alarm;
}
EVENT_TYPE CONTROL_CHAIN::EventStringToType(const string& event_name){
return _control_mngr->EventStringToType(event_name);
}
// Set late handler in all alarms
VOID CONTROL_CHAIN::SetLateHandler(){
for (UINT32 i = 0; i < _alarms.size(); i++){
_alarms[i]->SetLateHandler();
}
}
/// @endcond