Пример #1
0
//
// Perform the canonical last rites for a formerly alive child.
// Requires master lock held throughout.
//
void Child::bury(int status)
{
	assert(mState == alive);
	mState = dead;
	mStatus = status;
	mChildren().erase(mPid);
#if !defined(NDEBUG)
	if (bySignal())
		secdebug("unixchild", "%p (pid %d) died by signal %d%s",
			this, mPid, exitSignal(),
			coreDumped() ? " and dumped core" : "");
	else
		secdebug("unixchild", "%p (pid %d) died by exit(%d)",
			this, mPid, exitCode());
#endif //NDEBUG
}
Пример #2
0
void
BaseShadow::logRequeueEvent( const char* reason )
{
	struct rusage run_remote_rusage;
	memset( &run_remote_rusage, 0, sizeof(struct rusage) );

	run_remote_rusage = getRUsage();

	int exit_reason = getExitReason();

	JobEvictedEvent event;

	event.terminate_and_requeued = true;

	if( exitedBySignal() ) {
		event.normal = false;
		event.signal_number = exitSignal();
	} else {
		event.normal = true;
		event.return_value = exitCode();
	}
			
	if( exit_reason == JOB_COREDUMPED ) {
		event.setCoreFile( core_file_name );
	}

	if( reason ) {
		event.setReason( reason );
	}

		// TODO: fill in local rusage
		// event.run_local_rusage = r;
	event.run_remote_rusage = run_remote_rusage;

		/* we want to log the events from the perspective 
		   of the user job, so if the shadow *sent* the 
		   bytes, then that means the user job *received* 
		   the bytes */
	event.recvd_bytes = bytesSent();
	event.sent_bytes = bytesReceived();
	
	if (!uLog.writeEvent (&event,jobAd)) {
		dprintf( D_ALWAYS, "Unable to log ULOG_JOB_EVICTED "
				 "(and requeued) event\n" );
	}
}
Пример #3
0
// kind defaults to US_NORMAL.
void
BaseShadow::logTerminateEvent( int exitReason, update_style_t kind )
{
	struct rusage run_remote_rusage;
	JobTerminatedEvent event;
	MyString corefile;

	memset( &run_remote_rusage, 0, sizeof(struct rusage) );

	switch( exitReason ) {
	case JOB_EXITED:
	case JOB_COREDUMPED:
		break;
	default:
		dprintf( D_ALWAYS, 
				 "UserLog logTerminateEvent with unknown reason (%d), aborting\n",
				 exitReason ); 
		return;
	}

	if (kind == US_TERMINATE_PENDING) {

		int exited_by_signal = FALSE;
		int exit_signal = 0;
		int exit_code = 0;

		getJobAdExitedBySignal(jobAd, exited_by_signal);
		if (exited_by_signal == TRUE) {
			getJobAdExitSignal(jobAd, exit_signal);
			event.normal = false;
			event.signalNumber = exit_signal;
		} else {
			getJobAdExitCode(jobAd, exit_code);
			event.normal = true;
			event.returnValue = exit_code;
		}

		/* grab usage information out of job ad */
		double real_value;
		if( jobAd->LookupFloat(ATTR_JOB_REMOTE_SYS_CPU, real_value) ) {
			run_remote_rusage.ru_stime.tv_sec = (time_t) real_value;
		}

		if( jobAd->LookupFloat(ATTR_JOB_REMOTE_USER_CPU, real_value) ) {
			run_remote_rusage.ru_utime.tv_sec = (time_t) real_value;
		}

		event.run_remote_rusage = run_remote_rusage;
		event.total_remote_rusage = run_remote_rusage;
	
		/*
		  we want to log the events from the perspective of the user
		  job, so if the shadow *sent* the bytes, then that means the
		  user job *received* the bytes
		*/
		jobAd->LookupFloat(ATTR_BYTES_SENT, event.recvd_bytes);
		jobAd->LookupFloat(ATTR_BYTES_RECVD, event.sent_bytes);

		event.total_recvd_bytes = event.recvd_bytes;
		event.total_sent_bytes = event.sent_bytes;
	
		if( exited_by_signal == TRUE ) {
			jobAd->LookupString(ATTR_JOB_CORE_FILENAME, corefile);
			event.setCoreFile( corefile.Value() );
		}

		if (!uLog.writeEvent (&event,jobAd)) {
			dprintf (D_ALWAYS,"Unable to log "
				 	"ULOG_JOB_TERMINATED event\n");
			EXCEPT("UserLog Unable to log ULOG_JOB_TERMINATED event");
		}

		return;
	}

	// the default kind == US_NORMAL path

	run_remote_rusage = getRUsage();
	
	if( exitedBySignal() ) {
		event.normal = false;
		event.signalNumber = exitSignal();
	} else {
		event.normal = true;
		event.returnValue = exitCode();
	}

		// TODO: fill in local/total rusage
		// event.run_local_rusage = r;
	event.run_remote_rusage = run_remote_rusage;
		// event.total_local_rusage = r;
	event.total_remote_rusage = run_remote_rusage;
	
		/*
		  we want to log the events from the perspective of the user
		  job, so if the shadow *sent* the bytes, then that means the
		  user job *received* the bytes
		*/
	event.recvd_bytes = bytesSent();
	event.sent_bytes = bytesReceived();

	event.total_recvd_bytes = prev_run_bytes_recvd + bytesSent();
	event.total_sent_bytes = prev_run_bytes_sent + bytesReceived();
	
	if( exitReason == JOB_COREDUMPED ) {
		event.setCoreFile( core_file_name );
	}

#if 1
	set_usageAd(jobAd, &event.pusageAd);
#else
	std::string resslist;
	if ( ! jobAd->LookupString("PartitionableResources", resslist))
		resslist = "Cpus, Disk, Memory";

	StringList reslist(resslist.c_str());
	if (reslist.number() > 0) {
		int64_t int64_value = 0;
		ClassAd * puAd = new ClassAd();

		reslist.rewind();
		char * resname = NULL;
		while ((resname = reslist.next()) != NULL) {
			MyString attr;
			int64_value = -1;
			attr.formatstr("%s", resname); // provisioned value
			if (jobAd->LookupInteger(attr.Value(), int64_value)) {
				puAd->Assign(resname, int64_value);
			} 
			// /*for debugging*/ else { puAd->Assign(resname, 42); }
			int64_value = -2;
			attr.formatstr("Request%s", resname);	// requested value
			if (jobAd->LookupInteger(attr.Value(), int64_value)) {
				puAd->Assign(attr.Value(), int64_value);
			}
			// /*for debugging*/ else { puAd->Assign(attr.Value(), 99); }
			int64_value = -3;
			attr.formatstr("%sUsage", resname); // usage value
			if (jobAd->LookupInteger(attr.Value(), int64_value)) {
				puAd->Assign(attr.Value(), int64_value);
			}
		}
		event.pusageAd = puAd;
	}
#endif
	
	if (!uLog.writeEvent (&event,jobAd)) {
		dprintf (D_ALWAYS,"Unable to log "
				 "ULOG_JOB_TERMINATED event\n");
		EXCEPT("UserLog Unable to log ULOG_JOB_TERMINATED event");
	}
}
Пример #4
0
void
BaseShadow::terminateJob( update_style_t kind ) // has a default argument of US_NORMAL
{
	int reason;
	bool signaled;
	MyString str;

	if( ! jobAd ) {
		dprintf( D_ALWAYS, "In terminateJob() w/ NULL JobAd!" );
	}

	/* The first thing we do is record that we are in a termination pending
		state. */
	if (kind == US_NORMAL) {
		str.formatstr("%s = TRUE", ATTR_TERMINATION_PENDING);
		jobAd->Insert(str.Value());
	}

	if (kind == US_TERMINATE_PENDING) {
		// In this case, the job had already completed once and the
		// status had been saved to the job queue, however, for
		// some reason, the shadow didn't exit with a good value and
		// the job had been requeued. When this style of update
		// is used, it is a shortcut from the very birth of the shadow
		// to here, and so there will not be a remote resource or
		// anything like that set up. In this situation, we just
		// want to write the log event and mail the user and exit
		// with a good exit code so the schedd removes the job from
		// the queue. If for some reason the logging fails once again,
		// the process continues to repeat. 
		// This means at least once semantics for the termination event
		// and user email, but at no time should the job actually execute
		// again.

		int exited_by_signal = FALSE;
		int exit_signal = 0;
		int exit_code = 0;

		getJobAdExitedBySignal(jobAd, exited_by_signal);
		if (exited_by_signal == TRUE) {
			getJobAdExitSignal(jobAd, exit_signal);
		} else {
			getJobAdExitCode(jobAd, exit_code);
		}

		if (exited_by_signal == TRUE) {
			reason = JOB_COREDUMPED;
			str.formatstr("%s = \"%s\"", ATTR_JOB_CORE_FILENAME, core_file_name);
			jobAd->Insert(str.Value());
		} else {
			reason = JOB_EXITED;
		}

		dprintf( D_ALWAYS, "Job %d.%d terminated: %s %d\n",
	 		getCluster(), getProc(), 
	 		exited_by_signal? "killed by signal" : "exited with status",
	 		exited_by_signal ? exit_signal : exit_code );
		
			// write stuff to user log, but get values from jobad
		logTerminateEvent( reason, kind );

			// email the user, but get values from jobad
		emailTerminateEvent( reason, kind );

		DC_Exit( reason );
	}

	// the default path when kind == US_NORMAL

	// cleanup this shadow (kill starters, etc)
	cleanUp();

	reason = getExitReason();
	signaled = exitedBySignal();

	/* also store the corefilename into the jobad so we can recover this 
		during a termination pending scenario. */
	if( reason == JOB_COREDUMPED ) {
		str.formatstr("%s = \"%s\"", ATTR_JOB_CORE_FILENAME, getCoreName());
		jobAd->Insert(str.Value());
	}

    // Update final Job committed time
    int last_ckpt_time = 0;
    jobAd->LookupInteger(ATTR_LAST_CKPT_TIME, last_ckpt_time);
    int current_start_time = 0;
    jobAd->LookupInteger(ATTR_JOB_CURRENT_START_DATE, current_start_time);
    int int_value = (last_ckpt_time > current_start_time) ?
                        last_ckpt_time : current_start_time;

    if( int_value > 0 ) {
        int job_committed_time = 0;
        jobAd->LookupInteger(ATTR_JOB_COMMITTED_TIME, job_committed_time);
		int delta = (int)time(NULL) - int_value;
        job_committed_time += delta;
        jobAd->Assign(ATTR_JOB_COMMITTED_TIME, job_committed_time);

		float slot_weight = 1;
		jobAd->LookupFloat(ATTR_JOB_MACHINE_ATTR_SLOT_WEIGHT0, slot_weight);
		float slot_time = 0;
		jobAd->LookupFloat(ATTR_COMMITTED_SLOT_TIME, slot_time);
		slot_time += slot_weight * delta;
		jobAd->Assign(ATTR_COMMITTED_SLOT_TIME, slot_time);
    }

	CommitSuspensionTime(jobAd);

	// update the job ad in the queue with some important final
	// attributes so we know what happened to the job when using
	// condor_history...
    if (m_num_cleanup_retries < 1 &&
        param_boolean("SHADOW_TEST_JOB_CLEANUP_RETRY", false)) {
		dprintf( D_ALWAYS,
				 "Testing Failure to perform final update to job queue!\n");
		retryJobCleanup();
		return;
    }
	if( !updateJobInQueue(U_TERMINATE) ) {
		dprintf( D_ALWAYS, 
				 "Failed to perform final update to job queue!\n");
		retryJobCleanup();
		return;
	}

	// Let's maximize the effectiveness of that queue synchronization and
	// only record the job as done if the update to the queue was successful.
	// If any of these next operations fail and the shadow exits with an
	// exit code which causes the job to get requeued, it will be in the
	// "terminate pending" state marked by the ATTR_TERMINATION_PENDING
	// attribute.

	dprintf( D_ALWAYS, "Job %d.%d terminated: %s %d\n",
	 	getCluster(), getProc(), 
	 	signaled ? "killed by signal" : "exited with status",
	 	signaled ? exitSignal() : exitCode() );

	// write stuff to user log:
	logTerminateEvent( reason );

	// email the user
	emailTerminateEvent( reason );

	if( reason == JOB_EXITED && claimIsClosing() ) {
			// Startd not accepting any more jobs on this claim.
			// We do this here to avoid having to treat this case
			// identically to JOB_EXITED in the code leading up to
			// this point.
		dprintf(D_FULLDEBUG,"Startd is closing claim, so no more jobs can be run on it.\n");
		reason = JOB_EXITED_AND_CLAIM_CLOSING;
	}

	// try to get a new job for this shadow
	if( recycleShadow(reason) ) {
		// recycleShadow delete's this, so we must return immediately
		return;
	}

	// does not return.
	DC_Exit( reason );
}
Пример #5
0
void Tray::exitSlot ()
{
    emit ( exitSignal() );
}
Пример #6
0
MyWindow::MyWindow() : QWidget()
{
    pattern = 0;
    
    this->setFixedSize(940, 820);
    QObject::connect(this, SIGNAL(exitSignal()), qApp, SLOT(quit()));
    
    /* Generic area widgets */
    
    QString sim_data;
    QLabel *area = new QLabel, *nbr_enb = new QLabel, *nbr_ue = new QLabel, *nbr_frames = new QLabel, 
           *frame_format_label = new QLabel, *tdd_label = new QLabel;
    
    QGroupBox *generic = new QGroupBox("Generic Information", this);
    QFormLayout *generic_layout = new QFormLayout;
    generic_layout->setVerticalSpacing(10);
    generic_layout->setHorizontalSpacing(20);
    generic_frame = new QLabel("0");
    
    sim_data.sprintf("<html>%dm x %dm</html>", x_area, y_area);
    area->setText(sim_data);
  
    sim_data.sprintf("<html>%d</html>", nb_enb);
    nbr_enb->setText(sim_data);
  
    sim_data.sprintf("<html>%d</html>", nb_ue);
    nbr_ue->setText(sim_data);
    
    sim_data.sprintf("<html>%d</html>", nb_frames);
    nbr_frames->setText(sim_data);
    
    sim_data.sprintf("<html>%s</html>", frame_format);
    frame_format_label->setText(sim_data);
    
  
    
    sim_data.sprintf("<html>%d</html>", tdd_configuration);
    tdd_label->setText(sim_data);
    

    generic_layout->addRow(new QLabel("<html><u>Area dimensions:</u></html>"), area);
    generic_layout->addRow(new QLabel("<html><u>eNb node number:</u></html>"), nbr_enb);
    generic_layout->addRow(new QLabel("<html><u>UE node number:</u></html>"), nbr_ue);
    generic_layout->addRow(new QLabel("<html><u>Nb frames:</u></html>"), nbr_frames);
    generic_layout->addRow(new QLabel("<html><u>Frame format:</u></html>"), frame_format_label);
    generic_layout->addRow(new QLabel("<html><u>TDD configuration:</u></html>"), tdd_label);
    generic_layout->addRow(new QLabel("<html><FONT COLOR='blue' >Frame:</FONT></html>"), generic_frame);
   
    generic->setLayout(generic_layout);

    /* Control widgets */
    QCheckBox *drawConnections = new QCheckBox("Draw Connections");
    drawConnections->setChecked(true);
    QObject::connect(drawConnections, SIGNAL(stateChanged(int)), this, SLOT(setDrawConnections(int)));
    
    QCheckBox *useMap = new QCheckBox("Use a Map");
    useMap->setChecked(true);
    QObject::connect(useMap, SIGNAL(stateChanged(int)), this, SLOT(setUseMap(int)));
    
    QComboBox *nodes_color = new QComboBox(this);
    QComboBox *links_color = new QComboBox(this);
    used_map = new QComboBox(this);
    QHBoxLayout *nodes_color_layout = new QHBoxLayout(this);
    QHBoxLayout *links_color_layout = new QHBoxLayout(this);
    QHBoxLayout *used_map_layout = new QHBoxLayout(this);
    QLabel *nodes_color_label = new QLabel;
    QLabel *links_color_label = new QLabel;
    QLabel *used_map_label = new QLabel("Used map ");
    nodes_color_label->setText("Nodes color ");
    links_color_label->setText("Links color ");
    QFrame *node_color_frame = new QFrame;
    QFrame *link_color_frame = new QFrame;
    QFrame *used_map_frame = new QFrame;
    
    
    QString image;
    uri.sprintf("%s/UTIL/OMV/",getenv("OPENAIR2_DIR"));
    
    used_map->setIconSize(* (new QSize(20,20)));
    
    image = "jpg.jpeg";
    used_map->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Import map");
    
    image = "mus.png";
    used_map->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Mus");
    
    image = "new.jpg";
    used_map->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Trefoil");
    
    image = "new2.jpg";
    used_map->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Ocean");
    
    image = "white.png";
    used_map->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   White Bg");
    
    image = "red.png";
    used_map->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Red Bg");
    
    image = "green.png";
    used_map->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Green Bg");
    
    image = "blue.png";
    used_map->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Blue Bg");
    QObject::connect(used_map, SIGNAL(activated(int)), this, SLOT(setUsedMap(int)));
    
    nodes_color->setIconSize(* (new QSize(30,15)));
    
    image = "red.png";
    nodes_color->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Red");
    
    image = "blue.png";
    nodes_color->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Blue");
    
    image = "green.png";
    nodes_color->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Green");
    
    image = "white.png";
    nodes_color->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   White");
    QObject::connect(nodes_color, SIGNAL(currentIndexChanged(int)), this, SLOT(setNodesColor(int)));

    links_color->setIconSize(* (new QSize(30,15)));
    
    image = "white.png";
    links_color->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   White");
    
    image = "red.png";
    links_color->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Red");
    
    image = "blue.png";
    links_color->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Blue");
    
    image = "green.png";
    links_color->addItem(*(new QIcon (* (new QPixmap(uri + image)))),"   Green");
    QObject::connect(links_color, SIGNAL(currentIndexChanged(int)), this, SLOT(setLinksColor(int)));
    
    
    QFrame *node_size = new QFrame(this);
    QLabel *nodes_size_label = new QLabel("<html><b>Size:</b></html>");
    QLabel *min = new QLabel("Small");
    QLabel *max = new QLabel("Big");
    QSlider* size = new QSlider;
    size->setMinimum(1);
    size->setMaximum(3);
    size->setValue(2);
    size->setOrientation(Qt::Horizontal);
    QObject::connect(size, SIGNAL(sliderMoved(int)), this, SLOT(updateSize(int)));
    QHBoxLayout *size_layout = new QHBoxLayout;
    size_layout->addWidget(nodes_size_label);
    size_layout->addWidget(min);
    size_layout->addWidget(size);
    size_layout->addWidget(max);
    node_size->setLayout(size_layout);
    
    
    nodes_color_layout->addWidget(nodes_color_label);
    nodes_color_layout->addWidget(nodes_color);
    used_map_layout->addWidget(used_map_label);
    used_map_layout->addWidget(used_map);
    links_color_layout->addWidget(links_color_label);
    links_color_layout->addWidget(links_color);
    node_color_frame->setLayout(nodes_color_layout);
    link_color_frame->setLayout(links_color_layout);
    used_map_frame->setLayout(used_map_layout);
    
    
    /* Specific node widgets */
    QSpinBox* id_choice = new QSpinBox;
    id_choice->setRange(0,nb_ue - 1);
    QObject::connect(id_choice, SIGNAL(valueChanged(int)), this, SLOT(updateSupervNode(int)));
   
    
    QGroupBox *specific = new QGroupBox("Specific Information", this);
    QFormLayout *specific_layout = new QFormLayout;
    specific_layout->setVerticalSpacing(10);
    specific_layout->setHorizontalSpacing(40);
    
    specific_position = new QLabel("(0,0)");
    specific_state = new QLabel("Attached");
    specific_dist = new QLabel("100");
    specific_connected_enb = new QLabel("0");
    specific_pathloss = new QLabel("0");
    specific_rnti = new QLabel("0");
    specific_rsrp = new QLabel("0");
    specific_rsrq = new QLabel("0");
    
    rssi_tab = new QLabel[nb_antennas_rx];
    //ant_tab = new QLabel[nb_antennas_rx];
    
    QHBoxLayout *rssi = new QHBoxLayout;
    rssi->setSpacing(8);
    
    //QVBoxLayout *specific_layout = new QVBoxLayout;
    specific_layout->addRow(new QLabel("<html><b>UE Id  </b></html>"), id_choice);
    specific_layout->addRow(new QLabel("<html><b>Position  </b></html>"), specific_position);
    specific_layout->addRow(new QLabel("<html><b>State  </b></html>"), specific_state);
    specific_layout->addRow(new QLabel("<html><b>Connected eNb  </b></html>"), specific_connected_enb);
    specific_layout->addRow(new QLabel("<html><b>Dist. to eNb</b></html>"), specific_dist);
    specific_layout->addRow(new QLabel("<html><b>Pathloss</b></html>"), specific_pathloss);
    specific_layout->addRow(new QLabel("<html><b>RNTI</b></html>"), specific_rnti);
    specific_layout->addRow(new QLabel("<html><b>RSRP</b></html>"), specific_rsrp);
    specific_layout->addRow(new QLabel("<html><b>RSRQ</b></html>"), specific_rsrq);
    
    rssi->addWidget(new QLabel("<html><b>RSSI  </b></html>"));
    
    for (int ant = 0; ant < nb_antennas_rx; ant++){
	rssi_tab[ant].setAlignment(Qt::AlignCenter);
	rssi_tab[ant].setText("-1"); // to be taken from geo (struct) 
	rssi_tab[ant].setFrameStyle( QFrame::Raised | QFrame::Box );
	rssi_tab[ant].setFixedWidth(35);
	rssi->addWidget(&rssi_tab[ant]);
    }
    
    specific_layout->addRow(rssi);
    
    
    //specific_layout->addWidget(supervised_node);  
    specific->setLayout(specific_layout);
    
    QGroupBox *cntl = new QGroupBox("Control Panel", this);
    QVBoxLayout *cntl_layout = new QVBoxLayout;
    cntl_layout->addWidget(drawConnections);
    cntl_layout->addWidget(useMap);
    cntl_layout->addWidget(used_map_frame);
    cntl_layout->addWidget(node_color_frame);
    cntl_layout->addWidget(link_color_frame);
    cntl_layout->addWidget(node_size);
    cntl->setLayout(cntl_layout);

    /* Control area */
    control_field = new QFrame(this);
    control_field->setFrameShape(QFrame::StyledPanel);
    control_field->setFrameStyle( QFrame::Sunken | QFrame::Panel );
    control_field->setLineWidth( 2 );

    QVBoxLayout *control_layout = new QVBoxLayout;
    control_layout->addWidget(generic);
    control_layout->addWidget(specific);
    control_layout->addWidget(cntl);
    control_field->setLayout(control_layout);

    /* Drawing area */
    openGL_field = new QFrame(this);
    openGL_field->setFrameStyle( QFrame::Sunken | QFrame::Panel );
    openGL_field->setLineWidth( 2 );
    openGl = new OpenGLWidget();
    openGl->setFixedSize(620,540);
    QVBoxLayout *l1 = new QVBoxLayout;
    l1->addWidget(openGl);
    openGL_field->setLayout(l1);
    
    /* Console area */
    console_field = new QFrame(this);
    output = new QTextEdit();
    output->setReadOnly(true);
    QVBoxLayout *l2 = new QVBoxLayout;
    l2->addWidget(output);
    console_field->setLayout(l2);

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(openGL_field, 0, 0, 3, 3);
    layout->addWidget(control_field, 0, 3, 4, 1);
    layout->addWidget(console_field, 3, 0, 1, 3);

    this->setLayout(layout);

    communication_thread = new CommunicationThread(this);
    communication_thread->start();
}
Пример #7
0
void MyWindow::endOfTheSimulation(){
    communication_thread->wait();  // do not exit before the thread is completed!
    delete communication_thread;
    emit exitSignal();
}