Example #1
0
bool Task::isEqualTo(Task another){
	if (another.getDone() != _done){
		return false;
	}	
	switch(another.getType()){

	case FLOATING_TASK:
		return another.getTitle() == _title
			&& another.getType() == _type;
		break;
	case DEADLINE_TASK:
		return another.getTitle() == _title
			&& another.getEnd().compareTo(_end) == 0
			&& another.getType() == _type;
		break;
	case TIMED_TASK:
		return another.getTitle() == _title
			&& another.getStart().compareTo(_start) == 0
			&& another.getEnd().compareTo(_end) == 0
			&& another.getType() == _type;
		break;
	default:
		return false;
		break;
	}
	return false;
}
Example #2
0
bool Task::operator<(Task& a){
	
	if(a.getType() == TIMED_TASK)
		return (_start.compareTo(a.getStart()) < 0);
	else if(a.getType() == DEADLINE_TASK)
		return (_end.compareTo(a.getEnd()) < 0);
	else
		return false;
}
Example #3
0
void *Task::workerLoop(void *aux){
	ThreadData *data = (ThreadData *)aux;
	while (1){
		pthread_mutex_lock(&(data->mutex)); 
			while (data->t == NULL){
				pthread_cond_wait(&(data->todo), &(data->mutex)); 
			}
		Task* task = data->t;
		pthread_mutex_unlock(&(data->mutex)); 
		pthread_mutex_lock(&(task->lock));
		task->started = true; 
		pthread_mutex_unlock(&(task->lock));
		if (task->getType() == TASK_EXITER){
			data->status = THREAD_KILLED;
		}
		task->run();
		pthread_mutex_lock(&(task->lock));
		task->finished = true;
		pthread_cond_broadcast(&(task->wait)); 
		pthread_mutex_unlock(&(task->lock));
		data->status = THREAD_WAITING;
		data->parent->notifyDone(data);
	} 
	return NULL;  
}
Example #4
0
//
// Debug routine
//
//   This routine has no call, instead it is invoked in the debugger to display
//   the tasks currently queued at a context.  And to display the details of the
//   oldest task.
//
void displayContextTasks(map<ContextId, Context> &context, int id)
{
    Context tgt = context[id];
    Task* last;
    
    for (Task* t : tgt.tasks)
    {
        last = t;
        printf("%llx  ", t->getTaskId());
    }
    if (last != NULL)
    {
        cout << last->toString() << endl;
        
        if (last->getType() == task_type_join)
        {
            auto jc = tgt.joinCountMap.find(last->getTaskId());
            if (jc == tgt.joinCountMap.end())
            {
                cout << "Join is not waiting on any tasks, should be queued.\n";
            }
            else
            {
                cout << "Waiting on: " << jc->second << " tasks to join" << endl;
                for (TaskId s : last->getSuccessorTasks())
                {
                    if (tgt.joinMap.find(s.getContextId()) != tgt.joinMap.end())
                    {
                        cout << "\tWaiting on: " << s.toString() << endl;
                    }
                }
            }
        }
    }
}
Example #5
0
//
// Support routine to determine what is the blocking task
// 
//   Provided for being invoked by the debugger.  It scans the
//   blocked tasks in the background writing thread and finds
//   the oldest task.  And then reports what tasks have not been
//   sent to the background, such that this task cannot yet be written.
//
void debugBackground(map<TaskId, pair<Task*, int> > &tasks)
{
    Task* minT = NULL;
    ct_tsc_t minTsc = ~0;
    int predWait = 0;
    
    for (auto it = tasks.begin(), et = tasks.end(); it != et; ++it)
    {
        if (it->second.first->getStartTime() < minTsc)
        {
            minTsc = it->second.first->getStartTime();
            minT = it->second.first;
            predWait = it->second.second;
        }
    }
    
    if (minT != NULL)
    {
        cout << "Minimum Task is: ";
        cout << minT->getTaskId().toString() << " of type - ";
        cout << minT->getType() << endl;
        printf("Waiting on: %d tasks\n", predWait);
        for (TaskId p : minT->getPredecessorTasks())
        {
            if (tasks.find(p) == tasks.end())
            {
                printf("Predecessor: %s - Not Present\n", p.toString().c_str());
            }
            else
            {
                printf("Predecessor: %s - Present\n", p.toString().c_str());
            }
        }
    }
}
Example #6
0
// populateQueue
//   Populates the memory request queue with additional requests
int TraceWrapper::populateQueue()
{
    int addedMemOps = 0;
    Task* nextTask = NULL;

    // foreach task in graph
    //   Update running tasks based on the advancement in time represented by
    //   the new task
    while (pauseTask != NULL ||
           (nextTask = tg->getNextTask()))
    {
        Task* currentTask = nextTask;
        if (pauseTask != NULL)
        {
            currentTask = pauseTask;
            pauseTask = NULL;
        }
        TaskId ctui = currentTask->getTaskId();
        ContextId ctci = currentTask->getContextId();
        
        ct_timestamp start = currentTask->getStartTime();
        ct_timestamp req = currentTask->getEndTime();

        if (priorStart + 1000 > start)
        {
            ;// only advance to start
        }
        else
        {
            start = priorStart + 1000; // advance by 1000 cycles
        }
        priorStart = start;
        
        // Iterate through every basic block, older than start
        for (auto hs_b = contechState.begin(), hs_e = contechState.end(); hs_b != hs_e; ++hs_b)
        {
            ctid_current_state* tempState = (hs_b->second);
            if (tempState->terminated == true) continue;
            Task* t = tempState->currentTask;
            ct_timestamp tempCurrent = tempState->taskCurrTime;
            ct_timestamp tempRate = tempState->taskRate;
            auto f = tempState->currentBB;
            string s = t->getTaskId().toString();
            
            //
            // tempRate = 0 -> no basic blocks or currentTask->time == nextTask->time
            //   Still, process the basic blocks
            //
            for (auto e = tempState->currentBBCol.end(); 
                 (tempCurrent <= start) && (f != e); ++f)
            {
                BasicBlockAction tbb = *f;
                
                // Push MemOps onto queue
                auto memOps = f.getMemoryActions();
                MemReqContainer tReq;
                tReq.mav.clear();
                tReq.bbid = tbb.basic_block_id;
                tReq.ctid = (unsigned int) t->getContextId();
                uint32_t pushedOps = 0;
                for (auto iReq = memOps.begin(), eReq = memOps.end(); iReq != eReq; ++iReq)
                {
                    MemoryAction ma = *iReq;
                    
                
                    if (ma.type == action_type_mem_read || action_type_mem_write)
                    {
                        // Nothing special
                    }
                    else if (ma.type == action_type_memcpy)
                    {
                        tReq.mav.push_back(ma);
                        ++iReq;
                        pushedOps++;
                        ma = *iReq;
                        if (ma.type == action_type_memcpy)
                        {
                            tReq.mav.push_back(ma);
                            ++iReq;
                            pushedOps++;
                            ma = *iReq;
                        }
                    }
                    else if (ma.type == action_type_malloc)
                    {
                        tReq.mav.push_back(ma);
                        ++iReq;
                        pushedOps++;
                        ma = *iReq;
                    }
                    
                    pushedOps++;
                    tReq.mav.push_back(ma);
                
                    
                }
                assert(pushedOps == tReq.mav.size());
                
                if (pushedOps != 0)
                {
                    memReqQ.push(tReq);
                    addedMemOps += pushedOps;
                }
                
                tempCurrent += tempRate;
            }
            
            // Should the task switch always be from currentTask == next?
            //   o.w. The last basic block "spans" start
            if (ctui == tempState->nextTaskId)
            {
                bool tBlock = tempState->blocked;
                
                if (start < currentTask->getStartTime())
                {
                    pauseTask = currentTask;
                }
                
                //
                // Termination condition if the contech IDs change
                //   Or 0 is the successor task
                //
                if (t->getContextId() != tempState->nextTaskId.getContextId()
                    || tempState->nextTaskId == 0)
                {
                    delete t;
                    tempState->terminated = true;
                    continue;
                }
                
                // Is the new task running or doing something synchronizing?
                if (ctui == tempState->nextTaskId)
                {
                    tempState->currentTask = currentTask;
                }
                else
                {
                    tempState->currentTask = tg->getTaskById((tempState->nextTaskId));
                }
                
                assert(tempState->currentTask != NULL);
                
                if (tempState->currentTask->getType() == task_type_basic_blocks)
                    tempState->blocked = false;
                else
                    tempState->blocked = true;
                
                // If there is no continuation, then this task has terminated
                tempState->nextTaskId = getSequenceTask(tempState->currentTask->getSuccessorTasks(),
                                                        tempState->currentTask->getContextId());
                
                tempState->taskCurrTime = tempState->currentTask->getStartTime();
                tempState->currentBBCol = tempState->currentTask->getBasicBlockActions();
                tempState->currentBB = tempState->currentBBCol.begin();
                
                    
                // If the task is blocked, then it is not running.
                //  o.w. compute the task rate for this next task
                if (tempState->blocked == true)
                {
                    tempState->taskRate = 0;
                }
                else
                {
                    int bbc = tempState->currentTask->getBBCount();
                    if (bbc == 0)
                        bbc = 1;
                    tempState->taskRate = (tempState->currentTask->getEndTime() - tempState->taskCurrTime/* + bbc - 1*/) 
                                                / (bbc); 
                }
                delete t;
            }
            else if (tempCurrent < start)
            {
                tempState->blocked = true;
            }
            else
            {
                tempState->currentBB = f;
                tempState->taskCurrTime = tempCurrent;
            }
        }  // end of foreach task in contechState
        
        //
        // If ctci is not in contechState, then it is a new contech
        //   TODO: Due to barriers, it is possible that we'll need to "unterminate" some states
        //
        if (contechState.find(ctci) == contechState.end())
        {
            ctid_current_state* tempState = new ctid_current_state;
            
            tempState->terminated = false;
            tempState->taskCurrTime = start;
            tempState->currentBBCol = currentTask->getBasicBlockActions();
            tempState->currentBB = tempState->currentBBCol.begin();
            tempState->currentTask = currentTask;
            tempState->nextTaskId = getSequenceTask(tempState->currentTask->getSuccessorTasks(),
                                                    tempState->currentTask->getContextId());
            
            if (currentTask->getType() == task_type_basic_blocks)
            {
                tempState->blocked = false;
                tempState->taskRate = (tempState->currentTask->getEndTime() - start) / (currentTask->getBBCount());
            }
            else
            {
                tempState->blocked = true;
                tempState->taskRate = 0;
            }
            contechState[ctci] = tempState;
        }
        
        if (addedMemOps > 0) break;
    }
    
    return addedMemOps;
}
Example #7
0
void* backgroundTaskWriter(void* v)
{
    ct_file* out = *(ct_file**)v;

    deque<Task*> writeTaskQueue;
    map<TaskId, TaskWrapper> writeTaskMap;
    uint64 taskCount = 0, taskWriteCount = 0;
    
    uint64 bytesWritten = ct_tell(out);
    long pos;
    bool firstTime = true;
    unsigned int sec = 0, msec = 0, taskLastWriteCount = 0;
    
    //
    // noMoreTasks is a flag from the foreground thread
    //   And if there are no more, then there is the worklist of ready tasks
    //   And finally, there could still be tasks queued from the foreground
    // When all of those are clear, everything has been written.
    //
    while (!noMoreTasks ||
           (!writeTaskQueue.empty() || (taskQueue != NULL && !taskQueue->empty())))
    {
        deque<Task*>* taskChunk = NULL;
        
        //
        // Get tasks from the foreground
        //
        pthread_mutex_lock(&taskQueueLock);
        while (!noMoreTasks && taskQueue->empty())
        {
            pthread_cond_wait(&taskQueueCond, &taskQueueLock);
        }
        if (!noMoreTasks)
        {
            taskChunk = taskQueue;
            taskQueue = new deque<Task*>;
        }
        else
        {
            taskChunk = taskQueue;
            taskQueue = NULL;
            {
                struct timeb tp;
                ftime(&tp);
                printf("MIDDLE_DEQUE: %d.%03d\t%u\n", (unsigned int)tp.time, tp.millitm, taskWriteCount);
            }
        }
        pthread_mutex_unlock(&taskQueueLock);
    
        // Have a chunk of tasks from the foreground
        if (taskChunk != NULL)
        {
            writeTaskQueue.insert(writeTaskQueue.end(), taskChunk->begin(), taskChunk->end());
            taskCount += taskChunk->size();
            delete taskChunk;
        }
        
        
        while (!writeTaskQueue.empty())
        {
            Task* t = writeTaskQueue.front();
            TaskId id = t->getTaskId();
            
            writeTaskQueue.pop_front();
            
            // Task will be null if it has already been handled
            assert(t != NULL);
            // Write out the task
            pos = ct_tell(out);
            
            // TaskIndex is a graph, then use the graph to
            //   determine the bfs order, this way tasks can be written out
            //   immediately
            {
                TaskWrapper tw;
                
                tw.self = id;
                tw.start = t->getStartTime();
                tw.p = t->getPredecessorTasks().size();
                tw.s = t->getSuccessorTasks();
                tw.t = t->getType();
                tw.writePos = pos;
                assert(writeTaskMap.find(id) == writeTaskMap.end());
                writeTaskMap[id] = tw;
                
                /* Debugging code for bug where TaskId(x:0) had multiple predecessors
                if (id.getSeqId() == 0)
                {
                    printf("%u:%u -- ", id.getContextId(), id.getSeqId());
                    auto pr = t->getPredecessorTasks();
                    for (auto it = pr.begin(), et = pr.end(); it != et; ++it)
                    {
                        printf("%s\t", it->toString().c_str());
                    }
                    printf("\n");
                }*/
                //printf("%s", t->toSummaryString().c_str());
            }
            
            bytesWritten += Task::writeContechTask(*t, out);
            taskWriteCount += 1;
                
            // Delete the task
            delete t;
        }
        taskLastWriteCount = taskWriteCount;
    }
    
    // Write how many entries are in the index
    //   The write each index entry pair
    pos = ct_tell(out);
    if (pos == -1)
    {
        //int esav = errno;
        perror("Cannot identify index position");
    }
    {
        struct timeb tp;
        ftime(&tp);
        printf("MIDDLE_TASK: %d.%03d\n", (unsigned int)tp.time, tp.millitm);
    }
    printf("Writing index for %d at %lld\n", taskWriteCount, pos);
    size_t t = ct_write(&taskWriteCount, sizeof(taskWriteCount), out);
    
    priority_queue<pair<ct_tsc_t, pair<TaskId, uint64> >, vector<pair<ct_tsc_t, pair<TaskId, uint64> > >, first_compare > taskSort;
    
    {
        TaskWrapper tw = writeTaskMap.find(0)->second;
        taskSort.push(make_pair(tw.start, make_pair(tw.self, tw.writePos)));
    }
    
    //
    // This reproduces the BFS algorithm that had been used for writing tasks
    //   It is much faster to sort the tasks on just the graph information than
    //   to indefinitely delay writing a task until the entire graph is available.
    //
    // taskSort is a priority queue, the top element is the oldest task that has all
    //   its prior tasks in the index.
    //
    unsigned int indexWriteCount = 0;
    TaskId lastTid = 0;
    while (!taskSort.empty())
    {
        TaskId tid = taskSort.top().second.first;
        uint64 offset = taskSort.top().second.second;
        
        lastTid = tid;
        
        ct_write(&tid, sizeof(TaskId), out);
        ct_write(&offset, sizeof(uint64), out);
        //printf("%d:%d @ %llx\t", tid.getContextId(), tid.getSeqId(), offset);
        
        taskSort.pop();
        
        auto twit = writeTaskMap.find(tid);
        assert(twit != writeTaskMap.end());
        TaskWrapper tw = twit->second;
        
        assert(twit->first == tw.self);
        
        for (TaskId succ : tw.s)
        {
            TaskWrapper &suTW = writeTaskMap.find(succ)->second;
            
            //printf("%d:%d (%d)\t", succ.getContextId(), succ.getSeqId(), suTW.p);
            
            suTW.p--;
            if (suTW.p == 0)
            {
                taskSort.push(make_pair(suTW.start, make_pair(suTW.self, suTW.writePos)));
            }
        }
        //printf("\n");
        
        //  Can erase tid, but we don't need the memory, will it speed up?
        writeTaskMap.erase(twit);
        indexWriteCount ++;
    }
    printf("Wrote %u tasks to index\n", indexWriteCount);
    
    if (indexWriteCount != taskWriteCount)
    {
        for (auto it = writeTaskMap.begin(), et = writeTaskMap.end(); it != et; ++it)
        {
            printf("%s (type:%d) (pred:%d)\t", it->first.toString().c_str(), it->second.t, it->second.p);
            for (TaskId succ : it->second.s)
            {
                printf("%s\t", succ.toString().c_str());
            }
            printf("\n");
        }
    }
    
    // Failing this assert indicates that the graph either has cycles or is disjoint
    //   Both case are bad
    assert(indexWriteCount == taskWriteCount);
    
    // Now write the position of the index
    ct_seek(out, 4);
    
    // With ftell, we use long, rather than the uint64 type which we track positions
    ct_write(&pos, sizeof(pos), out);
    
    // Write the ROI start and end after index
    ct_write(&roiStart, sizeof(TaskId), out);
    if (roiEnd == 0)
    {
        roiEnd = lastTid;
    }
    ct_write(&roiEnd, sizeof(TaskId), out);
    
    //
    // Stats for the background thread.
    //  TaskCount should equal taskWriteCount
    //  And there should be no tasks remaining.
    //
    printf("Tasks Received: %ld\n", taskCount);
    printf("Tasks Written: %ld\n", taskWriteCount);
    if (taskQueue != NULL)
        printf("Tasks Left: %ld\n", taskQueue->size());
    printf("Tasks Remaining: %u\n", writeTaskQueue.size());
        
    return NULL;
}
Example #8
0
void updateContextTaskList(Context &c)
{
    // Non basic block tasks are handled by their creation logic
    //   basic block tasks can be queued, if they are not the newest task
    //   and they have a predecessor (i.e., have been created by another context).
    //   Task(0:0) has no predecessor and is a special case here.
    //
    // Creates must be complete when they are not the active task.  The child is
    //   known at creation time, so no update is required of this task.
    
    bool exited = (c.endTime != 0);
    
    // TODO: Should we 'cache' getType() or can the compiler do this?
    //   task_type tType ...
    
    if (exited == false)
    {
        for (auto it = c.tasks.begin(), et = c.tasks.end(); it != et; ++it)
        {
            Task* t = *it;
            if (t == c.activeTask()) continue;
            if (( t->getType() == task_type_basic_blocks &&
                (t->getPredecessorTasks().size() > 0 || t->getTaskId() == TaskId(0))) ||
               (t->getType() == task_type_create) ||
               (t->getType() == task_type_join && c.isCompleteJoin(t->getTaskId())))
            {
                // This is not guaranteed to remove every task in one pass;
                //   however, the routine will be invoked many times and it
                //   will correctly remove tasks.
                it = c.tasks.erase(it);
                backgroundQueueTask(t);
            }
        }
        
        /*while (t != c.activeTask() &&
               (( t->getType() == task_type_basic_blocks &&
                (t->getPredecessorTasks().size() > 0 || t->getTaskId() == TaskId(0))) ||
               (t->getType() == task_type_create) ||
               (t->getType() == task_type_join && c.isCompleteJoin(t->getTaskId()))))
              
        {
            c.tasks.pop_back();
            backgroundQueueTask(t);
            t = c.tasks.back();
        }*/
    }
    else
    {
        // If the context has exited, then even the active task can go
        if (c.tasks.empty()) return;
        Task* t = c.tasks.back();
        while (( t->getType() == task_type_basic_blocks &&
               (t->getPredecessorTasks().size() > 0 || t->getTaskId() == TaskId(0)) &&
               (t->getSuccessorTasks().size() > 0)) ||
               t->getType() == task_type_create)
        {
            c.tasks.pop_back();
            backgroundQueueTask(t);
            if (c.tasks.empty()) return;
            t = c.tasks.back();   
        }
    }
}
void ZerglingMicro::micro(BWAPI::Unit* unit)
{
	Task task = this->hc->ta->getTaskOfUnit(unit);
	
	UnitGroup allies = allEigenUnits().inRadius(dist(12), unit->getPosition());
	UnitGroup enemiesground = allEnemyUnits().inRadius(dist(10), unit->getPosition()).not(isFlyer);
	UnitGroup enemiesair = allEnemyUnits().inRadius(dist(7), unit->getPosition())(isFlyer);
	if(amountCanAttackGround(enemiesair) > 0 && amountCanAttackAir(allies) == 0)
	{
		unit->move(moveAway(unit));
	}
	else
	{
		if(task.getType() == ScoutTask)
		{
			if(allEnemyUnits().not(isBuilding).inRadius(dist(4), unit->getPosition()).size() > 0)
			{
				unit->move(moveAway(unit));
			}
			else
			{
				if(unit->getDistance(task.getPosition()) < dist(4) && BWAPI::Broodwar->isVisible(BWAPI::TilePosition(task.getPosition())))
				{
					if(!unit->isMoving())
					{
						int x = unit->getPosition().x();
						int y = unit->getPosition().y();
						int factor = dist(10);
						int newx = x + (((rand() % 30)-15)*factor);
						int newy = y + (((rand() % 30)-15)*factor);
						unit->move(BWAPI::Position(newx, newy).makeValid());
					}
				}
				else
				{
					unit->move(task.getPosition());
				}
			}
		}
		else
		{
			UnitGroup swarms = allUnits()(Dark_Swarm);
			BWAPI::Unit* swarm = getNearestUnit(unit->getPosition(), swarms);
			if(swarm != NULL && swarm->getPosition().getDistance(unit->getPosition()) < dist(9))
			{
				if(!isUnderDarkSwarm(unit) && !unit->isAttacking())
				{
					unit->attack(swarm->getPosition());
				}
				else
				{
					UnitGroup enemiesunderswarm = allEnemyUnits().inRadius(dist(6), unit->getPosition()).not(isFlyer);
					if(!unit->isAttacking() && enemiesunderswarm.size() > 0)
					{
						unit->attack(getNearestUnit(unit->getPosition(), enemiesunderswarm));
					}
				}
			}
			else
			{
				if(allies.size() < amountCanAttackGround(enemiesground))
				{
					unit->move(moveAway(unit));
				}
				else
				{
					if(enemiesground.inRadius(dist(3), unit->getPosition()).size() > 0)
					{
						// game AI
					}
					else
					{
						if(enemiesground.size() > 0)
						{
							BWAPI::Unit* nearest = getNearestUnit(unit->getPosition(), enemiesground);
							unit->attack(nearest);
						}
						else
						{
							UnitGroup* ug = this->hc->eiugm->getGroupOfUnit(unit);
							if(ug != NULL && tooSplitUp(dist(7), *ug))
							{
								BWAPI::Unit* nearest = getNearestUnit(ug->getCenter(), *ug);
								unit->attack(nearest);
							}
							else
							{
								unit->move(task.getPosition());
							}
						}
					}
				}
			}
		}
	}
}
Example #10
0
void SchemeMachine::performTask(){
	Task * task = tasks.pop(last_line);
	int n;

	switch(task->getType()){
	case Task::EVALUATE :
	{
		EvalTask * evtask;
		SchObjectRef * ref;
		int step;
		evtask = static_cast<EvalTask *>(task);
		ref = new SchObjectRef(*evtask->ref);
		last_line = (*ref)->getLine();
		step = evtask->step;
		delete task;
		(*ref)->evaluate(*this, step);
		delete ref;
	}
		break;
	case Task::CALL :
	{
		// tail recursion optimisation. if CALL and argument haz been evaluated --> del
		CallTask * ctask;
		ctask = static_cast<CallTask *>(task);
		int step = ctask->step;

		if(!tasks.isEmpty() && tasks.data[tasks.size-1]->getType() == Task::DEL_NAMES &&
				((*ctask->ref)->getType() != SchObject::SPECIAL || static_cast<SchSpecial *>(&**ctask->ref)->prepareArgs()))
		{
			// swap tasks
			Task * tmp = tasks.data[tasks.size-1]; // DEL_NAMES
			tasks.push(task);
			tasks.data[tasks.size-2] = tasks.data[tasks.size-1]; // DEL <- CALL
			tasks.data[tasks.size-1] = tmp; // CALL <- tmp
		} else {
			SchObjectRef * ref;
			ref = new SchObjectRef(*ctask->ref);
			last_line = (*ref)->getLine();
			n = ctask->n;
			delete task;
			(*ref)->call(*this, n, step);
			delete ref;
		}
	}
		break;
	case Task::EXECUTE :
	{
		ExecTask * extask;
		int step;
		bool must_swap = false;
		extask = static_cast<ExecTask *>(task);

		if(!tasks.isEmpty() && tasks.data[tasks.size-1]->getType() == Task::DEL_NAMES){
			if((*extask->ref)->getType() == SchObject::LIST){ // TODO
				must_swap = false;
			} else
			if((*extask->ref)->getType() != SchObject::SPECIAL){
				must_swap = true;
			} else
			if(static_cast<SchSpecial *>(&**extask->ref)->prepareArgs()){
				must_swap = true;
			}
		}

		if(must_swap) {
			// swap tasks
			Task * tmp = tasks.data[tasks.size-1]; // DEL_NAMES
			tasks.push(task);
			tasks.data[tasks.size-2] = tasks.data[tasks.size-1]; // DEL <- CALL
			tasks.data[tasks.size-1] = tmp; // CALL <- tmp
		} else {
			SchObjectRef * ref;
			ref = new SchObjectRef(*extask->ref);
			last_line = (*ref)->getLine();
			step = extask->step;
			n = extask->n;
			delete task;
			(*ref)->execute(*this, n, step);
			delete ref;
		}
	}
		break;
	case Task::ALIAS :
	{
		AliasTask * altask;
		altask = static_cast<AliasTask *>(task);
		global_names.push(altask->id, *(altask->ref));
		delete task;
	}
		break;
	case Task::ADD_NAMES :
	{
		AddNamesTask * atask;
		local_names_t * tmp;
		atask = static_cast<AddNamesTask *>(task);
		tmp = (typeof(tmp)) malloc (sizeof(*tmp));
		tmp->current = atask->map;
		tmp->prev = local_names;
		local_names = tmp;
		delete task;
	}
		break;
	case Task::DEL_NAMES :
	{
		delete task;
		if(local_names == NULL){
			throw LocalNamespaceUnderflowError(last_line);
		} else {
			local_names_t * tmp = local_names->prev;
			delete local_names->current;
			delete local_names;
			local_names = tmp;
		}
	}
		break;
	case Task::PRINT :
	{
		int N;
		SchObjectRef ** refs;
		N = static_cast<PrintTask *>(task)->N;
		refs = results.pop(N, last_line);
		for(int i = N-1; i >= 0; --i){
			(*refs[i])->print();
		}
		printf("\n");
		delete task;
	}
		break;
	case Task::PUSH_RESULT :
	{
		SchObjectRef * ref;
		ref = new SchObjectRef( * static_cast<PushResultTask *>(task)->ref );
		delete task;
		pushResult(*ref);
		delete ref;
	}
		break;
	case Task::NETWORK :
	{
		NetworkTask * ntask = static_cast<NetworkTask *>(task);
		int quantity = ntask->quantity, price = ntask->price, pid=ntask->player_id;

		if(ntask->gtype == NetworkTask::PERFORM){
			client->perform(ntask->subtype, quantity, price);
		} else {
			int res = client->getInfo(ntask->gtype, ntask->subtype, pid, quantity, price);
			pushResult(SchObjectRef(new SchInteger(last_line, res)));
		}

		delete task;
		break;
	}
	default:
		throw RuntimeError(last_line);
		break;
	}
}