How to continue after signal emission? - qt

I'm building a Othello game in Qt quick and C++.
I use this code from QML dialog to start new game, when one player is human, I wait for input. When two players are PC, I face the problem that the GUI will wait for the slot to finish, in PC players the slot call flipTurn() (because it is PC, no input to wait for), flipTurn is recursive, so the GUI will block until the game end.
I want it to update the board after each move. link for the project:
reversi project
myBroker.createGame(blacktypebutton.checkedButton.playertype,
whitetypebutton.checkedButton.playertype,
getBlackAlgo(),
getWhiteAlgo(),
getBlackDep(),
getWhiteDep());
console.log("finished creating game !");
void Broker::flipTurn()
{
if(someoneWon()){
emit gameEnd();
return;
}
emit updateBoard();
if (currentGame->getTurn() == Constants::BLACK){
currentGame->setTurn(Constants::WHITE);
if (currentGame->getWhitePlayer().getType() == Constants::PC){
currentGame->pcMove(Constants::WHITE);
flipTurn();
}
else
currentGame->updatePossible();
}
else{
currentGame->setTurn(Constants::BLACK);
if (currentGame->getBlackPlayer().getType() == Constants::PC){
currentGame->pcMove(Constants::BLACK);
flipTurn();
}
else
currentGame->updatePossible();
return;
}
emit updateBoard();
}
bool Broker::createGame(int blacktype, int whitetype, int blackalg, int whitealg, int blackdep, int whitedep)
{
currentGame = new Game(blacktype,whitetype,blackalg,whitealg,blackdep,whitedep);
currentGame->setGameBoard(&gameBoard);
updatePossible();
emit gameStart();
}
void Broker::onGameStart()
{
if(currentGame->getTurnType() == Constants::PC){
currentGame->pcMove(currentGame->getTurn());
cout<<"in ongamestart slot"<<endl;
flipTurn();
}
}

Since it is a turn based game, you will just need a different source to trigger the next turn.
Instead of calling flipTurn() directly, you call it through Qt's event loop.
Since you probably will want the human in front of the computer to see the game progressing, very likely with a delay.
For example with a single shot timer
// instead of calling flipTurn() directly
QTimer::singleShot(500, this, SLOT(flipTurn()));
Call next flipTurn() after 500 milliseconds.

I used
QCoreApplication::processEvents();
After each call to flipTurn() , so the GUI engine process any waiting signals (in my case the updateBoard() signal).
Although it isn't the best solution, it worked well for my homework.

Related

How to fix "In Qt two timer to one function, use qmutex will qeventloop for sleep"

I have some code use qtcpsocket to write and read,
write-->sleep-->read;
and ui had 2 and more timer to use this function; by i want i run synchronous;so i add mutex to lock it; by it deadlock;
qt4; qt5;
void MainWindow::Start()
{
pTimer = new QTimer(this);
pTimer->setInterval(100);
connect(pTimer,SIGNAL(timeout()), this, SLOT(OnTimer()) );
pTimer->start();
pTimer2 = new QTimer(this);
pTimer2->setInterval(100);
connect(pTimer2,SIGNAL(timeout()), this, SLOT(OnTimer()) );
pTimer2->start();
}
void MainWindow::OnTimer()
{
FunCal(); // in my real code it will MyObj.DoSometing();
}
void MainWindow::FunCal()
{
qDebug()<<"log in fun...";
QMutexLocker loc(&this->_mtx);
qDebug()<<"getted lock in fun...";
QEventLoop loop;
QTimer::singleShot(100, &loop, SLOT(quit()));
loop.exec();
qDebug()<<"log out fun...";
}
I Want i run and out put as:
log in fun...
getted lock in fun ...
log out fun...
log in fun...
getted lock in fun...
log out fun...
but It Run like this:
log in fun...
getted lock in fun ...
log in fun....
---------------------------------no more ---------------------
IMHO the issue of OP results from a basic misunderstanding:
QTimer doesn't introduce multithreading.
It's just a facility to queue events which will sent after a certain time.
That's why, the QEventLoop is necessary to make it running at all.
However, it's still a deterministic execution and this is what probably happens inside the code of OP:
pTimer->start(); → starts first timer
pTimer2->start(); → starts second timer
control flow returns to event loop of QApplication (not exposed in code)
first timer becomes due and calls MainWindow::FunCal()
qDebug()<<"log in fun..."; → output of log in fun...
QMutexLocker loc(&this->_mtx); → this->_mtx becomes locked
qDebug()<<"getted lock in fun..."; → output of getted lock in fun...
loop.exec(); → enter a nested event loop (Nested event loops are allowed in Qt.)
second timer becomes due and calls MainWindow::FunCal() (Please, remember that it was immediately started after first with same interval time.)
qDebug()<<"log in fun..."; → output of log in fun...
QMutexLocker loc(&this->_mtx); → PROBLEM!
To illustrate it further, imagine the following call stack at this point (above called below):
QApplication::exec()
QEventLoop::exec()
QEventLoop::processEvents()
QTimer::timerEvent()
QTimer::timeOut()
MainWindow::onTimer()
MainWindow::FunCal()
QEventLoop::exec()
QTimer::timerEvent()
QTimer::timeOut()
MainWindow::onTimer()
MainWindow::FunCal()
QMutexLocker::QMutexLocker()
QMutex::lock()
(Note: In reality, you will see much more entries in the call-stack which I considered as irrelevant details in this case.)
The problem is: This second call of MainWindow::FunCal() cannot lock the mutex because it is already locked. Hence, the execution is suspended until the mutex is unlocked but this will never happen. The locking of mutex happened in the same thread (in the first/outer call of MainWindow::FunCal()). Unlocking would require to return from this point but it cannot because it's suspended due to the locked mutex.
If you think this sounds like a cat byting into its own tail – yes, this impression is right. However, the official term is Deadlock.
The usage of a QMutex doesn't make much sense as long as there are no competing threads. In a single thread, a simple bool variable would do as well because there are no concurrent accesses possible in a single thread.
Whatever OP tried to achieve in this code: Concerning the event-based programming forced/required by Qt, the problem is simply modeled wrong.
In single threading, a function cannot be entered twice accept by
a (direct or indirect) recursive call
a call out of a triggered interrupt handler.
Leaving the 2. aside (irrelevant for OPs Qt issue), the recursive call happens explicitly due to establishing a second (nested) event loop. Without this, the whole (mutex) locking is unnecessary and should be removed as well.
To understand event-based programming in general – it's described in the Qt doc. The Event System.
Additionally, I found Another Look at Events by Jasmin Blanchette which IMHO gives a nice little introduction into how the Qt event-based execution works.
Note:
Event-based programming can become confusing as soon as the amount of involved objects and signals becomes large enough. While debugging my Qt applications, I noticed from time to time recursions which I didn't expect.
A simple example: A value is changed and emits a signal. One of the slots updates a Qt widget which emits a signal about modification. One of the slots updates the value. Hence, the value is changed and emits a signal...
To break such infinite recursions, a std::lock_guard might be used with a simple DIY class Lock:
#include <iostream>
#include <mutex>
#include <functional>
#include <cassert>
// a lock class
class Lock {
private:
bool _lock;
public:
Lock(): _lock(false) { }
~Lock() = default;
Lock(const Lock&) = delete;
Lock& operator=(const Lock&) = delete;
operator bool() const { return _lock; }
void lock() { assert(!_lock); _lock = true; }
void unlock() { assert(_lock); _lock = false; }
};
A sample object with
a property-like member: bool _value
a simplified signal emitter: std::function<void()> sigValueSet
and a lock used to prevent recursive calls to setValue(): Lock _lockValue
// a sample data class with a property
class Object {
private:
bool _value; // a value
Lock _lockValue; // a lock to prevent recursion
public:
std::function<void()> sigValueSet;
public:
Object(): _value(false) { }
bool value() const { return _value; }
void setValue(bool value)
{
if (_lockValue) return;
std::lock_guard<Lock> lock(_lockValue);
// assign value
_value = value;
// emit signal
if (sigValueSet) sigValueSet();
}
};
Finally, some code to force the lock into action:
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(Object obj);
std::cout << "obj.value(): " << obj.value() << '\n';
DEBUG(obj.sigValueSet = [&](){ obj.setValue(obj.value()); });
DEBUG(obj.setValue(true));
std::cout << "obj.value(): " << obj.value() << '\n';
}
To keep things short, I connected a slot to the signal which directly sets value again while the signal is emitted.
Output:
Object obj;
obj.value(): 0
obj.sigValueSet = [&](){ obj.setValue(obj.value()); };
obj.setValue(true);
obj.value(): 1
Live Demo on coliru
For a counter-example, I excluded the test if (_lockValue) return; and got the following output:
a.out: main.cpp:18: void Lock::lock(): Assertion `!_lock' failed.
Object obj;
obj.value(): 0
obj.sigValueSet = [&](){ obj.setValue(obj.value()); };
obj.setValue(true);
bash: line 7: 12214 Aborted (core dumped) ./a.out
Live Demo on coliru
This is similar to what happened in OPs case with the only difference that in my case double-locking just violated the assert().
To make this complete, I exluded the lock guard std::lock_guard<Lock> lock(_lockValue); as well and got the following output:
execution expired
Live Demo on coliru
The execution was trapped into an infinite recursion, and the online compiler aborted this after a certain time. (Sorry, coliru. I won't do it again.)

QTimer slot triggered for multiple time?

I'm creating a UI application for Raspberry PI to read data from sensor on definite timeout (5 seconds). Problem is the QTimer timeout slot is called for multiple times
{ //at system init
readTempCur = new QTimer(this);
connect(readTempCur, SIGNAL(timeout()), this, SLOT(readSensor()));
readTempCur->start(SAMPLINGTIME);
readSensor(); //added to call on boot itself, can be removed
}
void HomePage::readSensor(void) {
readTempCur->stop();
qDebug() << "Read Sensor triggerred at " <<QDateTime::currentDateTime().toString();
//DO my actions
readTempCur->start(SAMPLINGTIME);
}
[edit for answer]
The most probable case for such issue is conneccting the slot to the signal that already conneccted; this will trigger slot for 'n' number times it got connected, design should take care not to reconnect again.
The QTimer::start function will start/restart the timer.
Your readSensor function stops the timer and then restart it again.
remove the start to fix it.
void HomePage::readSensor(void) {
readTempCur->stop();
qDebug() << "Read Sensor triggerred at " <<QDateTime::currentDateTime().toString();
//DO my actions
//readTempCur->start(SAMPLINGTIME);
}
P.S.
If you want to run the timer once you can use the singleShoot
QTimer::singleShot(SAMPLINGTIME, this, SLOT(readSensor()));
Do not stop nor restart the timer in readSensor(). Just do:
void HomePage::readSensor(void)
{
qDebug() << "Read Sensor triggerred at " <<QDateTime::currentDateTime().toString();
//DO my actions
}
Also, make sure SAMPLINGTIME is given in milliseconds. For 5 seconds, SAMPLINGTIME should be 5000.

Pin interrupt being inconsistent

I'm trying out some beginner Arduino programming.
The task is to make the board I have (ESP8266) play some music and then the music should stop when I press the button, and then restart when I press it again.
Here's my code,
#include "pitches.h" // contains frequencies for notes
#define PIN_BUTTON 0 // the button
#define PIN_BUZZER 13 // the digital pin the Buzzer is attached to
bool stop = false; // button pressed
void play_note(int freq){
if (freq > 0 && !stop){
analogWrite(PIN_BUZZER, 512);
analogWriteFreq(freq);
} else {
analogWrite(PIN_BUZZER, 0);
}
}
void stopMusic(){
stop = !stop;
play_note(0);
}
void setup() {
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_BUTTON, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PIN_BUTTON), stopMusic, RISING);
}
void loop() {
// intro
play_note(NOTE_E7);
delay(110);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_C7);
delay(110);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_G7);
delay(440);
play_note(NOTE_G6);
delay(440);
}
The problem is, that the button is being inconsistent. Sometimes, on pressing it, the music will immediately stop. Other times, it will keep playing and I'll have to press it once or twice more. Similarly, when I want the music to start again, it will sometimes start as soon as I press the button, but other times I will need to press it twice or more to get the music back up. I don't know whats causing this. Suggestions?
The button is most likely a mechanical one. They bounce, i.e. open and close the contacts after a press or release for a short time. You have to wait until the button has settled (typically 5-20ms, actual value depends on the button and should be specified in the datasheet) before you check for a new value.
This is called de-bouncing.
Alternatively you can check the button from a periodic timer interrupt. But that would degrade reaction time.
You should probably add some debounce logic to your code.
https://www.arduino.cc/en/Tutorial/Debounce

How to update a TableView with progress data for multiple ProgressBars?

I've started to extend the qGet DownloadManager to emit the progress of a TransferItem, so that i can connect to it. I'm inserting the progress data into a cell of a TableView model for display with an Delegate, finally the delegate paints the progress bar. That works in theory, but i'm running into the following
Problem: when there are multiple downloads in parallel, then i get progress updates from both signals into both cells!
Both progress bars show progress data, but the signal is kind of mixed and not unique to the current index (QModelIndex index / index.row()).
(Please ignore the small transitioning problem between UserRoles (after clicking the download button "ActionCell" is displayed and then "Install", before the "ProgressBar" shows up.). That is not the main problem here. My question is about the index problem.) The text "112" and "113" is the int index.row.
Questions:
How to update a TableView with progress data for multiple ProgressBars?
What must i change to render a progress bar for each download?
Source
Emit progress of a download
I've added the following things to re-emit the signal through the classes, until it bubbles up to the top, where it becomes connectable from the GUI.
a connection from QNetworkReply - downloadProgress(qint64,qint64) to TransferItem - updateDownloadProgress(qint64,qint64)
void TransferItem::startRequest()
{
reply = nam.get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(updateDownloadProgress(qint64,qint64)));
connect(reply, SIGNAL(finished()), this, SLOT(finished()));
timer.start();
}
the SLOT function TransferItem - updateDownloadProgress(qint64,qint64) as receiver calculates the progress and stores it in progress (QMap<QString, QVariant>).
After the calculation the downloadProgress(this) signal is emitted.
// SLOT
void TransferItem::updateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
progress["bytesReceived"] = QString::number(bytesReceived);
progress["bytesTotal"] = QString::number(bytesTotal);
progress["size"] = getSizeHumanReadable(outputFile->size());
progress["speed"] = QString::number((double)outputFile->size()/timer.elapsed(),'f',0).append(" KB/s");
progress["time"] = QString::number((double)timer.elapsed()/1000,'f',2).append("s");
progress["percentage"] = (bytesTotal > 0) ? QString::number(bytesReceived*100/bytesTotal).append("%") : "0 %";
emit downloadProgress(this);
}
QString TransferItem::getSizeHumanReadable(qint64 bytes)
{
float num = bytes; QStringList list;
list << "KB" << "MB" << "GB" << "TB";
QStringListIterator i(list); QString unit("bytes");
while(num >= 1024.0 && i.hasNext()) {
unit = i.next(); num /= 1024.0;
}
return QString::fromLatin1("%1 %2").arg(num, 3, 'f', 1).arg(unit);
}
When a new download is enqueued, i'm connecting the emitted downloadProgress(this) to the Slot DownloadManager - downloadProgress(TransferItem*). (dl is DownloadItem which extends TransferItem).
void DownloadManager::get(const QNetworkRequest &request)
{
DownloadItem *dl = new DownloadItem(request, nam);
transfers.append(dl);
FilesToDownloadCounter = transfers.count();
connect(dl, SIGNAL(downloadProgress(TransferItem*)),
SLOT(downloadProgress(TransferItem*)));
connect(dl, SIGNAL(downloadFinished(TransferItem*)),
SLOT(downloadFinished(TransferItem*)));
}
Finally, i'm re-emitting the download progress one more time:
void DownloadManager::downloadProgress(TransferItem *item)
{
emit signalProgress(item->progress);
}
Now the TableView with Delegate, doDownload(index) and ProgressBarUpdater
QTableView
with added QSortFilterProxyModel (for case-insensitivity)
with added ColumnDelegate, which renders DownloadButton and ProgressBar based on custom UserRoles. The delegate handles the button click: the SIGNAL downloadButtonClicked(index) is emited from the editorEvent(event, model, option, index) method.
actionDelegate = new Updater::ActionColumnItemDelegate;
ui->tableView->setItemDelegateForColumn(Columns::Action, actionDelegate);
connect(actionDelegate, SIGNAL(downloadButtonClicked(QModelIndex)), this, SLOT(doDownload(QModelIndex)));
The doDownload method receives the index and fetches the download URL from the model. Then the URL is added to the DownloadManager
and i'm setting up a ProgressBarUpdater object to set the progress data to the model at the given index. Finally i'm, connecting downloadManager::signalProgress to progressBar::updateProgress and invoke the downloadManager::checkForAllDone to start the download processing.
void UpdaterDialog::doDownload(const QModelIndex &index)
{
QUrl downloadURL = getDownloadUrl(index);
if (!validateURL(downloadURL)) return;
QNetworkRequest request(downloadURL);
downloadManager.get(request); // QueueMode is Parallel by default
ProgressBarUpdater *progressBar = new ProgressBarUpdater(this, index.row());
progressBar->setObjectName("ProgressBar_in_Row_" + QString::number(index.row()) );
connect(&downloadManager, SIGNAL(signalProgress(QMap<QString, QVariant>)),
progressBar, SLOT(updateProgress(QMap<QString, QVariant>)));
QMetaObject::invokeMethod(&downloadManager, "checkForAllDone", Qt::QueuedConnection);
}
The model update part: the ProgressBarUpdater takes the index and the progress and should update the model at the given index.
ProgressBarUpdater::ProgressBarUpdater(UpdaterDialog *parent, int currentIndexRow) :
QObject(parent), currentIndexRow(currentIndexRow)
{
model = parent->ui->tableView_1->model();
}
void ProgressBarUpdater::updateProgress(QMap<QString, QVariant> progress)
{
QModelIndex actionIndex = model->index(currentIndexRow, UpdaterDialog::Columns::Action);
// set progress to model
model->setData(actionIndex, progress, ActionColumnItemDelegate::DownloadProgressBarRole);
model->dataChanged(actionIndex, actionIndex);
}
The rendering part: i'm rendering the fake ProgressBar from the delegate; fetching the progress data with index.model()->data(index, DownloadProgressBarRole).
void ActionColumnItemDelegate::drawDownloadProgressBar(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionProgressBarV2 opt;
opt.initFrom(bar);
opt.rect = option.rect;
opt.rect.adjust(3,3,-3,-3);
opt.textVisible = true;
opt.textAlignment = Qt::AlignCenter;
opt.state = QStyle::State_Enabled | QStyle::State_Active;
// get progress from model
QMap<QString, QVariant> progress =
index.model()->data(index, DownloadProgressBarRole).toMap();
QString text = QString::fromLatin1(" %1 %2 %3 %4 %5 ")
.arg(QString::number(index.row()))
.arg(progress["percentage"].toString())
.arg(progress["size"].toString())
.arg(progress["speed"].toString())
.arg(progress["time"].toString());
opt.minimum = 0;
opt.maximum = progress["bytesTotal"].toFloat();
opt.progress = progress["bytesReceived"].toFloat();
opt.text = text;
bar->style()->drawControl(QStyle::CE_ProgressBar,&opt,painter,bar);
}
I've added QString::number(index.row() to the progress bar text, so that each ProgressBar gets its row number rendered. In other words: the rendering is unique to the row, but the incoming progress data is somehow mixed.
I'm stuck on the index problem for a while now. Thank you in advance for your help.
Update: The issue is resolved!
Thank you very much ddriver!! I followed your suggestions and fixed it:
The DownloadManager tracks the progress for all transfers, and you keep each transfer item's data in the respective TransferItem.
The logical thing IMO would be to have a connection from each TransferItem to the corresponding ProgressBarUpdater, and emit from the transfer item.
However, in your case, you are reporting progress not from each individual transfer item, but from the download manager. So each time you are emitting a progress, you are emitting the progress for a particular transfer item to all progress bars.
connect(&downloadManager, SIGNAL(signalProgress(QMap<QString, QVariant>)),
progressBar, SLOT(updateProgress(QMap<QString, QVariant>)));
So instead of a
TransferItem --progress--> CorrespondingUI
you have a:
TransferItem --transferItem--> DownloadManager --progress--> AllUIs
This leads to having one single and varying progress for all progress bars, which corresponds to the last download that happen to report progress before the UI updated. Which is why you get no more variation after the first download is completed, as the manager only updates the progress for the second.
Finally, i'm re-emitting the download progress one more time:
void DownloadManager::downloadProgress(TransferItem *item)
{
emit signalProgress(item->progress);
}
And who exactly needs an anonymous progress, containing no information whatsoever to which transfer it applies? Aside from the bug of course.
Would you be so nice to explain, how to simplify it?
I was at the end of my mental rope yesterday when I commented, on a clear head it doesn't look all that overdone, but still I'd probably go for something more streamlined, involving 3 key components only:
DownloadsManager -> DownloadController -> UI
-> DownloadController -> UI
It just seems redundant to have a DownloadItem and then also a TransferItem, considering that a download is a transfer.
The model and view are totally unnecessary as well, as is storing the progress in the model rather than just having it as a member of the progress bar. You could go with just a regular widget for each download, and place them in a vertical layout.
Update:
The excessive, unnecessary compartmentalization has led to a level of fragmentation which makes it hard to get to the data, needed to make it work once you put everything together. The main issue is you have no way to tie a transfer item to the right progress bar updater, and since you still haven't posted all of the relevant code, the simplest possible solution I can offer involves the following minor changes:
// in DownloadManager
void signalProgress(QMap<QString, QVariant>); // this signal is unnecessary, remove
void DownloadManager::downloadProgress(TransferItem *item) // change this
{
registry[item->request.url()]->updateProgress(item->progress);
}
QMap<QUrl, ProgressBarUpdater *> registry; // add this
// in UpdaterDialog
void UpdaterDialog::doDownload(const QModelIndex &index)
{
QUrl downloadURL = getDownloadUrl(index);
if (!validateURL(downloadURL)) return;
QNetworkRequest request(downloadURL);
downloadManager.get(request); // QueueMode is Parallel by default
ProgressBarUpdater *progressBar = new ProgressBarUpdater(this, index.row());
progressBar->setObjectName("ProgressBar_in_Row_" + QString::number(index.row()) );
// remove the connection - source of the bug, instead register the updater
downloadManager.registry[downloadURL] = progressBar;
QMetaObject::invokeMethod(&downloadManager, "checkForAllDone", Qt::QueuedConnection);
}
That's pretty much it, the progress updater is associated with the URL, and in DownloadManager::downloadProgress instead of emitting the progress to all progress updaters, you simply lookup the one which actually corresponds to the particular download, and only update its progress. It is somewhat clumsy, but as I said, if your design is proper, it would not be needed and you wouldn't have the problem in the first place.
There are other solutions as well:
change the DownloadManager's signal to void signalProgress(TransferItem *), and the body of downloadProgress toemit signalProgress(item); , change to void ProgressBarUpdater::updateProgress(TransferItem *), and in the body compare the transfer item's request's url to the one in the model at the currentIndexRow, and only model-setData() if it is the same. This solution is not very efficient, since it will emit to all progress updaters just to modify one.
cut out the middleman, what I've been suggesting from the start, make DownloadManager ::get() return a pointer to the DownloadItem/TransferItem created in its body, then in UpdaterDialog::doDownload() you can connect the transfer item directly to the appropriate progress updater, so you will no longer need DownloadManager::downloadProgress() and the signalProgress signal, you only need to change the signature of the signal in TransferItem to void downloadProgress(QMap<QString, QVariant>); and emit the progress rather than the item. This is actually the most efficient solution, as it involves nothing extra, jsut the removal of unnecessary stuff.

why does ptrace singlestep return a too big instruction count when statically linking it?

So, I've already read this article Counting machine instructions of a process using PTRACE_SINGLESTEP, and i understand that dynamically linking a testprogram to my ptrace program will return an instruction count that also counts the initialization of the run-time library. However, I'm trying to get a valid count for my test program, which is:
int main(){
return 0;
}
My ptrace program first also returned 90k+ values, so I changed it to statically linking the used testprogram. The counter is now less, but still over 12k. The program I used to count the instructions is:
#include <sys/ptrace.h>
#include <unistd.h>
#include <stdio.h>
int main() {
long long counter = 1; // machine instruction counter
int wait_val; // child's return value
int pid; // child's process id
int dat;
switch (pid = fork()) { // copy entire parent space in child
case -1: perror("fork");
break;
case 0: // child process starts
ptrace(PTRACE_TRACEME,0,NULL,NULL);
/*
must be called in order to allow the
control over the child process and trace me (child)
0 refers to the parent pid
*/
execl("./returntestprog","returntestprog",NULL);
/*
executes the testprogram and causes
the child to stop and send a signal
to the parent, the parent can now
switch to PTRACE_SINGLESTEP
*/
break;
// child process ends
default: // parent process starts
wait(&wait_val);
if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0) != 0)
perror("ptrace");
/*
switch to singlestep tracing and
release child
if unable call error.
*/
wait(&wait_val);
// parent waits for child to stop at next
// instruction (execl())
while (wait_val == 1407) {
counter++;
if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0) != 0)
perror("ptrace");
/*
switch to singlestep tracing and
release child
if unable call error.
*/
wait(&wait_val);
// wait for next instruction to complete */
}
/*
continue to stop, wait and release until
the child is finished; wait_val != 1407
Low=0177L and High=05 (SIGTRAP)
*/
}
printf("Number of machine instructions : %lld\n", counter);
return 0;
} // end of switch
Any help would be really appreciated as I'm not quite sure if it's working right, or not at all. Once I get this thing started, I want to work on timing analysis with ptrace, but first things first and try to count the number of executed instructions
thanks!
I've kind of figured it out by now. So even when statically linking your code, you try to prevent the libraries to be dynamically linked to your program and thus also included into your count. The other side of it however is that executing your file, or basically invoking under the operating system also takes an enormous amount of instructions. So basically, as long as the instruction count is constant and the same under the same conditions, you can subtract this count (when using a return 0 program for instance) from your original program, to count the real number of instructions.

Resources