From: Ethan A M. <merritt@u.washington.edu> - 2014-02-12 19:45:04
|
On Wednesday, 12 February, 2014 13:24:38 Yuriy Kaminskiy wrote: > > 423 while (qt->socket.bytesAvailable() >= (int)sizeof(gp_event_t)) > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > Not sure, but this looks very wrong. If this condition ever triggers (there are > less than sizeof(...) bytes in socket), it will result in infinite busy-loop (if > there are *any* bytes in socket, waitForReadyRead will instantly return, > receivedFontProps is not changed, bytesAvailable check will fail again, etc). > > I think same apply to similar code in qt_waitforinput(). > > (However, it is unlikely to be related to discussed bug (I expect it can only > trigger on gnuplot and gnuplot_qt version/ABI/architecture mismatch). Still, it > feels a way too fragile; You are correct. I'll work up a fix. > IMO, there should be at very least mutual validation of > sizeof(gp_event_t) at startup). Maybe, but there are other things that are more likely to go wrong if there is a version mismatch. Ethan |
From: Daniel J S. <dan...@ie...> - 2014-02-13 02:31:26
|
On 02/12/2014 03:24 AM, Yuriy Kaminskiy wrote: > Daniel J Sebald wrote: >> Looking at the debugger results below, it seems that qt_term.cpp is >> having problems at or near lines 423-424: >> >>> 748,772,... [0x1001da24c,0x1001da264,...] qt_term.cpp:424 >>> + 118 qt_sendFont() (in gnuplot) + >>> 737,713,... [0x1001da241,0x1001da229,...] qt_term.cpp:423 >>> + 110 >> >> and the code hunk around there is: >> >> while (!receivedFontPropos) >> { >> qt->socket.waitForReadyRead(1000); >> 423 while (qt->socket.bytesAvailable()>= (int)sizeof(gp_event_t)) > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > Not sure, but this looks very wrong. If this condition ever triggers (there are > less than sizeof(...) bytes in socket), it will result in infinite busy-loop (if > there are *any* bytes in socket, waitForReadyRead will instantly return, > receivedFontProps is not changed, bytesAvailable check will fail again, etc). > > I think same apply to similar code in qt_waitforinput(). > > (However, it is unlikely to be related to discussed bug (I expect it can only > trigger on gnuplot and gnuplot_qt version/ABI/architecture mismatch). Still, it > feels a way too fragile; IMO, there should be at very least mutual validation of > sizeof(gp_event_t) at startup). I agree. In previous posts I didn't put much thought into "good" fixes for these loops because, as you say, it seems too fragile. If I have time this weekend I'll see if I can put something together using signals/slots. It shouldn't be difficult. Dan |
From: sfeam <sf...@us...> - 2014-02-10 00:55:23
|
On Sunday, 09 February 2014 12:29:34 PM Mojca Miklavec wrote: > On Sun, Feb 9, 2014 at 12:11 PM, Mojca Miklavec wrote: > > On Sun, Feb 9, 2014 at 1:19 AM, sfeam wrote: > >> On Sunday, 09 February 2014 01:01:20 AM Mojca Miklavec wrote: > >>> > Another possible test: > >>> > Change the timeout value on line 259 from > >>> > qt->socket.waitForConnected(200); > >>> > to > >>> > qt->socket.waitForConnected(-1); > >>> > > >>> > This could potentially cause gnuplot to hang, but it also might work > >>> > >>> Gnuplot runs at 99% CPU with or without that change (just gnuplot, That makes very little sense to me, but see below. > >>> gnuplot_qt doesn't consume any CPU at a > >> gnuplot is spinning CPU cycles while waiting for a timeout? > >> The OSX implementation must really suck. > >> Anyhow if you can see the gnuplot_qt process but the waitForConnected > >> fails to return that's probably a huge clue to what's gone wrong. > >> Let me think about this for a while. > >> > >> I'm cc-ing Jérôme Lodewyck. Maybe he can decipher the clue. > > > > I don't know if that's a clue or not, but if I run gdb and manually > > press "n", only a single gnuplot_qt is started and gnuplot actually > > returns to the console (if I simply run gnuplot, it runs at 99% CPU > > "forever"). The first "plot sin(x)" doesn't show anything, but when I > > plot something for the second time, the plot is actually shown. > > > > So maybe there's just a problem of wrong > > timing/synchronisation/initialisation somewhere after all. > > > > The fact is that if I actually get to this point (by manually stepping > > inside gdb), it works a lot better than it did with forking: > > - printing doesn't crash > > - there is no need for the dirty hack removeDockIcon() > > TransformProcessType(&psn, kProcessTransformToBackgroundApplication); > > to hide the nofunctional window > According to a gdb a lot of that "infinite cycling" (when not properly > connected) happens with > > while (!receivedFontPropos) > qt->socket.waitForReadyRead(1000); > while (qt->socket.bytesAvailable() >= (int)sizeof(gp_event_t)) > } It should not be possible for that while {} construction to gobble CPU. It only wakes up and checks the socket once per second. Unless (which I'm beginning to suspect) all the 1000 msec timeouts are acting as NOOPs on OSX. Could it really be that Qt on OSX doesn't implement event-driven waits? > And indeed if I change the timeout: > > --- a/src/qtterminal/qt_term.cpp > +++ b/src/qtterminal/qt_term.cpp > @@ -251,7 +252,7 > > // The QLocalSocket::waitForConnected does not respect the > time out argument when the > // gnuplot_qt application is not yet started. To wait for it, > we need to implement the timeout ourselves > - QDateTime timeout = QDateTime::currentDateTime().addMSecs(1000); > + QDateTime timeout = QDateTime::currentDateTime().addMSecs(10000); > do > { > qt->socket.connectToServer(server); > > it suddenly almost starts working. I'm saying almost because the first > plot doesn't work, but the second one does. Hence my suspicion that timeouts < 1000msec are not working. I suggest you do a global search and replace for timeouts and make sure they are all >1000 msec. > Terminal type set to 'qt' > gnuplot> plot sin(x) # nothing can be seen > started detached process "qtgnuplot31706" > gnuplot> plot cos(x) # works > gnuplot> > > It seems that gnuplot gives up too quickly. And if it does give up, > the second attempt to connect doesn't work properly, ends up with two > instances of gnuplot_qt running (none of them gets closed etc). > > The following is "sampling" of the running gnuplot at 99% CPU: > > Call graph: > 2510 Thread_2393718 DispatchQueue_1: com.apple.main-thread (serial) > + 2510 start (in gnuplot) + 52 [0x100011244] > + 2510 main (in gnuplot) + 2796 [0x1000aa62c] plot.c:672 > + 2510 com_line (in gnuplot) + 144 [0x100025140] command.c:323 > + 2510 do_line (in gnuplot) + 1066 [0x10002559a] command.c:411 > + 2510 command (in gnuplot) + 131 [0x100026283] command.c:616 > + 2510 plot_command (in gnuplot) + 206 [0x100028d1e] > command.c:1559 > + 2510 plotrequest (in gnuplot) + 1763 [0x1000abf83] > plot2d.c:273 > + 2510 eval_plots (in gnuplot) + 27828 > [0x1000c00c4] plot2d.c:3259 > + 2510 do_plot (in gnuplot) + 131 [0x100062843] > graphics.c:517 > + 2510 term_start_plot (in gnuplot) + 63 > [0x10011476f] term.c:557 > + 2510 qt_graphics (in gnuplot) + 669 > [0x1001da68d] qt_term.cpp:480 > + 1582 qt_sendFont() (in gnuplot) + 772 > [0x1001da264] qt_term.cpp:424 > + ! 962 QLocalSocket::bytesAvailable() const > (in QtNetwork) + 42 [0x1022520fa] > + ! : 646 QAbstractSocket::bytesAvailable() > const (in QtNetwork) + 16 [0x102245210] > + ! : | 646 QIODevice::bytesAvailable() > const (in QtCore) + 0,20,... [0x1030389a0,0x1030389b4,...] > + ! : 248 QAbstractSocket::bytesAvailable() > const (in QtNetwork) + 0,16,... [0x102245200,0x102245210,...] > + ! : 68 > DYLD-STUB$$QIODevice::bytesAvailable() const (in QtNetwork) + 0 > [0x10226ca8a] > + ! 295 QLocalSocket::bytesAvailable() const > (in QtNetwork) + 16 [0x1022520e0] > + ! : 295 QIODevice::bytesAvailable() const > (in QtCore) + 0,85,... [0x1030389a0,0x1030389f5,...] > + ! 236 QLocalSocket::bytesAvailable() const > (in QtNetwork) + 6,16,... [0x1022520d6,0x1022520e0,...] > + ! 89 > DYLD-STUB$$QIODevice::bytesAvailable() const (in QtNetwork) + 0 > [0x10226ca8a] > + 342 qt_sendFont() (in gnuplot) + 737 > [0x1001da241] qt_term.cpp:423 > + ! 195 QLocalSocket::waitForReadyRead(int) > (in QtNetwork) + 6,51,... [0x1022526c6,0x1022526f3,...] > + ! 147 QLocalSocket::waitForReadyRead(int) > (in QtNetwork) + 18 [0x1022526d2] > + ! 147 QLocalSocket::state() const (in > QtNetwork) + 0,8 [0x10224aed0,0x10224aed8] > + 180 qt_sendFont() (in gnuplot) + > 748,772,... [0x1001da24c,0x1001da264,...] qt_term.cpp:424 > + 118 qt_sendFont() (in gnuplot) + > 737,713,... [0x1001da241,0x1001da229,...] qt_term.cpp:423 > + 110 > DYLD-STUB$$QLocalSocket::waitForReadyRead(int) (in gnuplot) + 0 > [0x1001e38b6] > + 97 > DYLD-STUB$$QLocalSocket::bytesAvailable() const (in gnuplot) + 0 > [0x1001e38ec] > + 47 qt_sendFont() (in gnuplot) + 695 > [0x1001da217] qt_term.cpp:421 > + 34 qt_sendFont() (in gnuplot) + 999 > [0x1001da347] qt_term.cpp:437 > 2510 Thread_2393731 DispatchQueue_2: > com.apple.libdispatch-manager (serial) > + 2510 _dispatch_mgr_thread (in libdispatch.dylib) + 54 [0x7fff8c328316] > + 2510 _dispatch_mgr_invoke (in libdispatch.dylib) + 923 > [0x7fff8c329786] > + 2510 kevent (in libsystem_kernel.dylib) + 10 [0x7fff8b5e27e6] > 2510 Thread_2393735: QProcessManager > 2510 thread_start (in libsystem_c.dylib) + 13 [0x7fff89671b75] > 2510 _pthread_start (in libsystem_c.dylib) + 335 [0x7fff8966e8bf] > 2510 QThreadPrivate::start(void*) (in QtCore) + 504 [0x102fad238] > 2510 QProcessManager::run() (in QtCore) + 168 [0x10307d7b8] > 2510 __select (in libsystem_kernel.dylib) + 10 [0x7fff8b5e1df2] > > Total number in stack (recursive counted multiple, when >=5): > > Sort by top of stack, same collapsed (when >= 5): > __select (in libsystem_kernel.dylib) 2510 > kevent (in libsystem_kernel.dylib) 2510 > QIODevice::bytesAvailable() const (in QtCore) 941 > qt_sendFont() (in gnuplot) 379 > QAbstractSocket::bytesAvailable() const (in QtNetwork) 248 > QLocalSocket::bytesAvailable() const (in QtNetwork) 236 > QLocalSocket::waitForReadyRead(int) (in QtNetwork) 195 > DYLD-STUB$$QIODevice::bytesAvailable() const (in QtNetwork) 157 > QLocalSocket::state() const (in QtNetwork) 147 > DYLD-STUB$$QLocalSocket::waitForReadyRead(int) (in gnuplot) 110 > DYLD-STUB$$QLocalSocket::bytesAvailable() const (in gnuplot) 97 > > Mojca Finally a trace that makes sense in that it involves a recent change. This bit belongs to the patch: 2014-01-26 Jérôme Lodewyck <lod...@us...> * src/qtterminal/qt_term.cpp: Implement font metric caching. This solves a flickering issue when a large number of font changes are called (for example when rotating the world plot in world2.dem). * src/qtterminal/QtGnuplotInstance.*: New public function that sends a command to gnuplot and blocks until it receives the answer. Can you back out just that one set of changes from current CVS and see if that makes your qt terminal work? If it doesn't, then add in the larger timeouts and check again. We can probably make this font-related stuff work, but first let's try to disentangle it from any fork+exec+sync timing problems. Ethan |
From: Ethan A M. <sf...@us...> - 2014-02-11 20:33:49
|
On Sunday, 09 February, 2014 16:57:36 sfeam wrote: > > And indeed if I change the timeout: > > > > --- a/src/qtterminal/qt_term.cpp > > +++ b/src/qtterminal/qt_term.cpp > > @@ -251,7 +252,7 > > > > // The QLocalSocket::waitForConnected does not respect the > > time out argument when the > > // gnuplot_qt application is not yet started. To wait for it, > > we need to implement the timeout ourselves > > - QDateTime timeout = QDateTime::currentDateTime().addMSecs(1000); > > + QDateTime timeout = QDateTime::currentDateTime().addMSecs(10000); > > do > > { > > qt->socket.connectToServer(server); > > > > it suddenly almost starts working. I'm saying almost because the first > > plot doesn't work, but the second one does. > > Hence my suspicion that timeouts < 1000msec are not working. > I suggest you do a global search and replace for timeouts and make > sure they are all >1000 msec. I think I have uncovered part of the problem, but I do not understand why it is failing. This loop: do { qt->socket.connectToServer(server); qt->socket.waitForConnected(200); // TODO: yield CPU ? } while(...) Does not work as intended. To see why, change it to this: qDebug() << "qt_connectToServer " << server; do { qt->socket.connectToServer(server); if (!qt->socket.waitForConnected(TIMEOUT)) qDebug() << qt->socket.errorString(); usleep(50000); } while(...) Regardless of the value of TIMEOUT, including -1 or blank, the waitForConnected returns immediately with an error: "QLocalSocket::connectToServer: Invalid name" Without the usleep() it spews hundreds or even thousands of these errors before fallling through to the rest of the code. The usleep reduces this to a manageable number of error reports. So the first connection attempts always fail, even under linux, and the failure is immediate. Why is it an invalid name? I don't know. How does it eventually succeed? I don't know that either. Since TIMEOUT is ignored this is becomes a CPU-burning loop, which is what Mojca originally reported. The usleep should fix that, and a large enough manual timeout as in QDateTime timeout = QDateTime::currentDateTime().addMSecs(30000); may in fact be necessary. But it would be nice to understand the real reason why the initial connection attempts fail, because maybe we can test and wait on that condition directly and avoid the useless loop here. Ethan |
From: Thomas B. <Tho...@gm...> - 2014-02-11 21:15:35
|
* Ethan A Merritt <sf...@us...> [2014-02-11 21:35]: > On Sunday, 09 February, 2014 16:57:36 sfeam wrote: > > > And indeed if I change the timeout: > > > > > > --- a/src/qtterminal/qt_term.cpp > > > +++ b/src/qtterminal/qt_term.cpp > > > @@ -251,7 +252,7 > > > > > > // The QLocalSocket::waitForConnected does not respect the > > > time out argument when the > > > // gnuplot_qt application is not yet started. To wait for it, > > > we need to implement the timeout ourselves > > > - QDateTime timeout = QDateTime::currentDateTime().addMSecs(1000); > > > + QDateTime timeout = QDateTime::currentDateTime().addMSecs(10000); > > > do > > > { > > > qt->socket.connectToServer(server); > > > > > > it suddenly almost starts working. I'm saying almost because the first > > > plot doesn't work, but the second one does. > > > > Hence my suspicion that timeouts < 1000msec are not working. > > I suggest you do a global search and replace for timeouts and make > > sure they are all >1000 msec. > > I think I have uncovered part of the problem, but I do not understand > why it is failing. > > This loop: > do > { > qt->socket.connectToServer(server); > qt->socket.waitForConnected(200); > // TODO: yield CPU ? > } > while(...) > > Does not work as intended. > > To see why, change it to this: > qDebug() << "qt_connectToServer " << server; > do > { > qt->socket.connectToServer(server); > if (!qt->socket.waitForConnected(TIMEOUT)) > qDebug() << qt->socket.errorString(); > usleep(50000); > } > while(...) > > Regardless of the value of TIMEOUT, including -1 or blank, the > waitForConnected returns immediately with an error: > "QLocalSocket::connectToServer: Invalid name" [Note: I haven't looked at this in detail, so these are just my guesses] I think the error is probably a race condition: - gnuplot starts the external gnuplot_qt process - Immediately afterwards it tries to connect to the socket from gnuplot_qt - Depending on scheduling, gnuplot_qt may have had a chance to run or not. But in any case it needs to do some initialization first. So my guess is that the "Invalid name" error stems from the fact that during the first iteration of the loop, the named pipe (which is created by gnuplot_qt) is simply not there yet. I also looked through the recent changes to the gnuplot code just now, and noticed that no QApplication object is created anymore in gnuplot. According to the docs, waitForConnected() should also work without an event loop, but I think it would still be interesting to see if the high CPU usage goes away if QCoreApplication is replaced by QApplication. Just my 2cents. Thomas > Without the usleep() it spews hundreds or even thousands of these errors > before fallling through to the rest of the code. The usleep reduces this > to a manageable number of error reports. > So the first connection attempts always fail, even under linux, and the > failure is immediate. > Why is it an invalid name? I don't know. > How does it eventually succeed? I don't know that either. > > Since TIMEOUT is ignored this is becomes a CPU-burning loop, > which is what Mojca originally reported. The usleep should fix that, and a > large enough manual timeout as in > QDateTime timeout = QDateTime::currentDateTime().addMSecs(30000); > may in fact be necessary. But it would be nice to understand the real > reason why the initial connection attempts fail, because maybe we can > test and wait on that condition directly and avoid the useless loop here. > > Ethan |
From: Daniel J S. <dan...@ie...> - 2014-02-12 05:36:20
|
On 02/11/2014 03:15 PM, Thomas Bleher wrote: > * Ethan A Merritt<sf...@us...> [2014-02-11 21:35]: >> On Sunday, 09 February, 2014 16:57:36 sfeam wrote: >>>> And indeed if I change the timeout: >>>> >>>> --- a/src/qtterminal/qt_term.cpp >>>> +++ b/src/qtterminal/qt_term.cpp >>>> @@ -251,7 +252,7 >>>> >>>> // The QLocalSocket::waitForConnected does not respect the >>>> time out argument when the >>>> // gnuplot_qt application is not yet started. To wait for it, >>>> we need to implement the timeout ourselves >>>> - QDateTime timeout = QDateTime::currentDateTime().addMSecs(1000); >>>> + QDateTime timeout = QDateTime::currentDateTime().addMSecs(10000); >>>> do >>>> { >>>> qt->socket.connectToServer(server); >>>> >>>> it suddenly almost starts working. I'm saying almost because the first >>>> plot doesn't work, but the second one does. >>> >>> Hence my suspicion that timeouts< 1000msec are not working. >>> I suggest you do a global search and replace for timeouts and make >>> sure they are all>1000 msec. >> >> I think I have uncovered part of the problem, but I do not understand >> why it is failing. >> >> This loop: >> do >> { >> qt->socket.connectToServer(server); >> qt->socket.waitForConnected(200); >> // TODO: yield CPU ? >> } >> while(...) >> >> Does not work as intended. >> >> To see why, change it to this: >> qDebug()<< "qt_connectToServer "<< server; >> do >> { >> qt->socket.connectToServer(server); >> if (!qt->socket.waitForConnected(TIMEOUT)) >> qDebug()<< qt->socket.errorString(); >> usleep(50000); >> } >> while(...) >> >> Regardless of the value of TIMEOUT, including -1 or blank, the >> waitForConnected returns immediately with an error: >> "QLocalSocket::connectToServer: Invalid name" > > [Note: I haven't looked at this in detail, so these are just my guesses] > > I think the error is probably a race condition: > - gnuplot starts the external gnuplot_qt process > - Immediately afterwards it tries to connect to the socket from > gnuplot_qt > - Depending on scheduling, gnuplot_qt may have had a chance to run or > not. But in any case it needs to do some initialization first. > > So my guess is that the "Invalid name" error stems from the fact that > during the first iteration of the loop, the named pipe (which is created > by gnuplot_qt) is simply not there yet. This is correct, but also how the software is designed. It continues in a loop until it can find the pipe or timeout occurs. I've printed out the server name on my linux box and there is a stream of: . . . Server: "qtgnuplot13225" Server: "qtgnuplot13225" Server: "qtgnuplot13225" Server: "qtgnuplot13225" gnuplot> before the plot appears. So it probably isn't too difficult for 1 second to go by at the system level before an application is up and running. So, I'd say make that timeout just a tad longer. Notice that this is a recurrent function. When the timeout does occur, eventually the logic gets to: if (connectToWidget) { qDebug() << "Could not connect to widget" << qt_option->Widget << ". Starting a QtGnuplotApplication"; qt_option->Widget = QString(); qt_connectToServer(qt->localServerName); } so that calls this function a second time, but at the top of the function there is bool connectToWidget = (server != qt->localServerName); So then what happens if there is a second failure to connect? Well, then the logic becomes: else { qDebug() << "Could not connect gnuplot_qt" << qt_option->Widget << ". Starting a new one"; execGnuplotQt(); qt_connectToServer(qt->localServerName, false); } and the argument is 'false' so will not try after the third time. In any case, I suggest adding the sleep as Ethan has done. There is no reason that should be running at 100%. In fact, there is probably a preferred way to do this without polling loops. I learned a little bit about Qt working on Octave and Qt has this paradigm of signals and slots and the developers suggest adhering to the concept otherwise can get kind of dodgy (not in this simple case...but cases where widget IDs are floating about). signal: something that a Qt object emits slot: the destination of the signal which can be of any number, e.g., five other objects could connect a slot to a signal Anyhow, I don't have time to look at this right now, but if one looks at the documentation for a Qt socket: http://qt-project.org/doc/qt-4.8/qlocalsocket.html#connectToServer it indicates that a signal is emitted when the connection is complete and there is a signal emitted when there is an error. So the proper thing to do is to first make connections to the socket sort of like the following ("success" and "failed" are custom member functions): connect (createdsocket, SIGNAL (connected ()), watcher, SLOT (success ())); connect (createdsocket, SIGNAL (error ()), watcher, SLOT (failed ())); and then tell the socket to attempt to connect to the server: createdsocket->connectToServer (name) There is no need to check in a loop for anything. Either the socket will successfully connect and emit "connected" at which point "success()" will get called or the socket will timeout and emit "error" at which point "failed()" will get called. One can get very creative about connections made, the number of slots watching a signal, doing this dynamically, etc. So instead of a recursive routine, it might be multiple connections, or dynamically reconnect/disconnect in the "failed()" slot. Etc. Dan |
From: Thomas B. <Tho...@gm...> - 2014-02-12 20:49:30
|
* Daniel J Sebald <dan...@ie...> [2014-02-12 06:36]: > In any case, I suggest adding the sleep as Ethan has done. There is > no reason that should be running at 100%. In fact, there is > probably a preferred way to do this without polling loops. I > learned a little bit about Qt working on Octave and Qt has this > paradigm of signals and slots and the developers suggest adhering to > the concept otherwise can get kind of dodgy (not in this simple > case...but cases where widget IDs are floating about). > > signal: something that a Qt object emits > slot: the destination of the signal which can > be of any number, e.g., five other > objects could connect a slot to a signal > > Anyhow, I don't have time to look at this right now, but if one > looks at the documentation for a Qt socket: > > http://qt-project.org/doc/qt-4.8/qlocalsocket.html#connectToServer > > it indicates that a signal is emitted when the connection is > complete and there is a signal emitted when there is an error. So > the proper thing to do is to first make connections to the socket > sort of like the following ("success" and "failed" are custom member > functions): > > connect (createdsocket, SIGNAL (connected ()), watcher, SLOT (success ())); > connect (createdsocket, SIGNAL (error ()), watcher, SLOT (failed ())); > > and then tell the socket to attempt to connect to the server: > > createdsocket->connectToServer (name) > > There is no need to check in a loop for anything. Either the socket > will successfully connect and emit "connected" at which point > "success()" will get called or the socket will timeout and emit > "error" at which point "failed()" will get called. > > One can get very creative about connections made, the number of > slots watching a signal, doing this dynamically, etc. So instead of > a recursive routine, it might be multiple connections, or > dynamically reconnect/disconnect in the "failed()" slot. Etc. signals and slots are indeed very nice, but they need a Qt event loop to work correctly. I don't think it is possible to add the Qt event loop to gnuplot without major surgery. (Well, you can start a local event loop using QEventLoop inside a function, but in this case it's just more work to get the same result we already have). Thomas |
From: Daniel J S. <dan...@ie...> - 2014-02-13 02:50:26
|
On 02/12/2014 02:49 PM, Thomas Bleher wrote: > * Daniel J Sebald<dan...@ie...> [2014-02-12 06:36]: >> In any case, I suggest adding the sleep as Ethan has done. There is >> no reason that should be running at 100%. In fact, there is >> probably a preferred way to do this without polling loops. I >> learned a little bit about Qt working on Octave and Qt has this >> paradigm of signals and slots and the developers suggest adhering to >> the concept otherwise can get kind of dodgy (not in this simple >> case...but cases where widget IDs are floating about). >> >> signal: something that a Qt object emits >> slot: the destination of the signal which can >> be of any number, e.g., five other >> objects could connect a slot to a signal >> >> Anyhow, I don't have time to look at this right now, but if one >> looks at the documentation for a Qt socket: >> >> http://qt-project.org/doc/qt-4.8/qlocalsocket.html#connectToServer >> >> it indicates that a signal is emitted when the connection is >> complete and there is a signal emitted when there is an error. So >> the proper thing to do is to first make connections to the socket >> sort of like the following ("success" and "failed" are custom member >> functions): >> >> connect (createdsocket, SIGNAL (connected ()), watcher, SLOT (success ())); >> connect (createdsocket, SIGNAL (error ()), watcher, SLOT (failed ())); >> >> and then tell the socket to attempt to connect to the server: >> >> createdsocket->connectToServer (name) >> >> There is no need to check in a loop for anything. Either the socket >> will successfully connect and emit "connected" at which point >> "success()" will get called or the socket will timeout and emit >> "error" at which point "failed()" will get called. >> >> One can get very creative about connections made, the number of >> slots watching a signal, doing this dynamically, etc. So instead of >> a recursive routine, it might be multiple connections, or >> dynamically reconnect/disconnect in the "failed()" slot. Etc. > > signals and slots are indeed very nice, but they need a Qt event loop to > work correctly. I don't think it is possible to add the Qt event loop to > gnuplot without major surgery. (Well, you can start a local event loop > using QEventLoop inside a function, but in this case it's just more work > to get the same result we already have). Good point, but we'll see if we can make it work somehow. It's worth at least a couple hours time to test whether it is feasible. It would seem that the place to start the Qt event loop along with setting up initial signals/slots would be upon calling "term qt". The good thing is that the graphics is done in the satellite Qt program. The bits accessible to gnuplot core don't need graphics, so perhaps that Qt event loop could be run in a different, non-main thread without too much work. Local event loop might work, but that seems like a lot of overhead to communicate every time with a remote program with any sort of high bandwidth. Local event loops are what dialog boxes can and often use. Overhead isn't an issue there. Dan |
From: sfeam <sf...@us...> - 2014-02-13 04:11:42
|
On Wednesday, 12 February 2014 08:50:18 PM Daniel J Sebald wrote: > On 02/12/2014 02:49 PM, Thomas Bleher wrote: > > * Daniel J Sebald<dan...@ie...> [2014-02-12 06:36]: > >> In any case, I suggest adding the sleep as Ethan has done. There is > >> no reason that should be running at 100%. In fact, there is > >> probably a preferred way to do this without polling loops. I > >> learned a little bit about Qt working on Octave and Qt has this > >> paradigm of signals and slots and the developers suggest adhering to > >> the concept otherwise can get kind of dodgy (not in this simple > >> case...but cases where widget IDs are floating about). > >> > >> signal: something that a Qt object emits > >> slot: the destination of the signal which can > >> be of any number, e.g., five other > >> objects could connect a slot to a signal > >> > >> Anyhow, I don't have time to look at this right now, but if one > >> looks at the documentation for a Qt socket: > >> > >> http://qt-project.org/doc/qt-4.8/qlocalsocket.html#connectToServer > >> > >> it indicates that a signal is emitted when the connection is > >> complete and there is a signal emitted when there is an error. So > >> the proper thing to do is to first make connections to the socket > >> sort of like the following ("success" and "failed" are custom member > >> functions): > >> > >> connect (createdsocket, SIGNAL (connected ()), watcher, SLOT (success ())); > >> connect (createdsocket, SIGNAL (error ()), watcher, SLOT (failed ())); > >> > >> and then tell the socket to attempt to connect to the server: > >> > >> createdsocket->connectToServer (name) > >> > >> There is no need to check in a loop for anything. Either the socket > >> will successfully connect and emit "connected" at which point > >> "success()" will get called or the socket will timeout and emit > >> "error" at which point "failed()" will get called. > >> > >> One can get very creative about connections made, the number of > >> slots watching a signal, doing this dynamically, etc. So instead of > >> a recursive routine, it might be multiple connections, or > >> dynamically reconnect/disconnect in the "failed()" slot. Etc. > > > > signals and slots are indeed very nice, but they need a Qt event loop to > > work correctly. I don't think it is possible to add the Qt event loop to > > gnuplot without major surgery. (Well, you can start a local event loop > > using QEventLoop inside a function, but in this case it's just more work > > to get the same result we already have). > > Good point, but we'll see if we can make it work somehow. It's worth at > least a couple hours time to test whether it is feasible. It would seem > that the place to start the Qt event loop along with setting up initial > signals/slots would be upon calling "term qt". The good thing is that > the graphics is done in the satellite Qt program. The bits accessible > to gnuplot core don't need graphics, so perhaps that Qt event loop could > be run in a different, non-main thread without too much work. > > Local event loop might work, but that seems like a lot of overhead to > communicate every time with a remote program with any sort of high > bandwidth. Local event loops are what dialog boxes can and often use. > Overhead isn't an issue there. I don't agree that an event loop is needed for this particular purpose. We don't have a case of asynchronous processes sending each other signals at random times. We just want some way for the daughter process to signal back to the parent process "I'm ready now, you can proceed". And we want some way for the parent to wait for this signal without burning CPU cycles. One would think from its name that QLocalSocket::waitForConnected() provides exactly this service, but evidently it doesn't. At least in linux it should be possible to have the parent call sigwait(), and the daughter call kill(parent_pid, SIGUSR1). No need to involve Qt in this. Ethan |
From: Daniel J S. <dan...@ie...> - 2014-02-13 04:53:32
|
On 02/12/2014 10:14 PM, sfeam wrote: > On Wednesday, 12 February 2014 08:50:18 PM Daniel J Sebald wrote: >> On 02/12/2014 02:49 PM, Thomas Bleher wrote: >>> * Daniel J Sebald<dan...@ie...> [2014-02-12 06:36]: >>>> In any case, I suggest adding the sleep as Ethan has done. There is >>>> no reason that should be running at 100%. In fact, there is >>>> probably a preferred way to do this without polling loops. I >>>> learned a little bit about Qt working on Octave and Qt has this >>>> paradigm of signals and slots and the developers suggest adhering to >>>> the concept otherwise can get kind of dodgy (not in this simple >>>> case...but cases where widget IDs are floating about). >>>> >>>> signal: something that a Qt object emits >>>> slot: the destination of the signal which can >>>> be of any number, e.g., five other >>>> objects could connect a slot to a signal >>>> >>>> Anyhow, I don't have time to look at this right now, but if one >>>> looks at the documentation for a Qt socket: >>>> >>>> http://qt-project.org/doc/qt-4.8/qlocalsocket.html#connectToServer >>>> >>>> it indicates that a signal is emitted when the connection is >>>> complete and there is a signal emitted when there is an error. So >>>> the proper thing to do is to first make connections to the socket >>>> sort of like the following ("success" and "failed" are custom member >>>> functions): >>>> >>>> connect (createdsocket, SIGNAL (connected ()), watcher, SLOT (success ())); >>>> connect (createdsocket, SIGNAL (error ()), watcher, SLOT (failed ())); >>>> >>>> and then tell the socket to attempt to connect to the server: >>>> >>>> createdsocket->connectToServer (name) >>>> >>>> There is no need to check in a loop for anything. Either the socket >>>> will successfully connect and emit "connected" at which point >>>> "success()" will get called or the socket will timeout and emit >>>> "error" at which point "failed()" will get called. >>>> >>>> One can get very creative about connections made, the number of >>>> slots watching a signal, doing this dynamically, etc. So instead of >>>> a recursive routine, it might be multiple connections, or >>>> dynamically reconnect/disconnect in the "failed()" slot. Etc. >>> >>> signals and slots are indeed very nice, but they need a Qt event loop to >>> work correctly. I don't think it is possible to add the Qt event loop to >>> gnuplot without major surgery. (Well, you can start a local event loop >>> using QEventLoop inside a function, but in this case it's just more work >>> to get the same result we already have). >> >> Good point, but we'll see if we can make it work somehow. It's worth at >> least a couple hours time to test whether it is feasible. It would seem >> that the place to start the Qt event loop along with setting up initial >> signals/slots would be upon calling "term qt". The good thing is that >> the graphics is done in the satellite Qt program. The bits accessible >> to gnuplot core don't need graphics, so perhaps that Qt event loop could >> be run in a different, non-main thread without too much work. >> >> Local event loop might work, but that seems like a lot of overhead to >> communicate every time with a remote program with any sort of high >> bandwidth. Local event loops are what dialog boxes can and often use. >> Overhead isn't an issue there. > > I don't agree that an event loop is needed for this particular purpose. > We don't have a case of asynchronous processes sending each other > signals at random times. We just want some way for the daughter > process to signal back to the parent process "I'm ready now, you can > proceed". And we want some way for the parent to wait for this > signal without burning CPU cycles. One would think from its name that > QLocalSocket::waitForConnected() provides exactly this service, but > evidently it doesn't. At least in linux it should be possible to have the > parent call sigwait(), and the daughter call kill(parent_pid, SIGUSR1). > No need to involve Qt in this. Well, if there were some way to communicate with the Qt satellite program without using any Qt code in the terminal that might be fine. But I think a lot of these networking and timer Qt function might need a Qt event loop running in order for them to work properly: " http://qt-project.org/wiki/ThreadsEventsQObjects What requires a running event loop? This isn’t an exhaustive list, but if you have the overall picture, you should be able to guess which classes require a running event loop. Widgets painting and interaction: [don't have that] Timers: [not directly, but if we are asking something to timeout maybe internally] Networking: all low-level Qt networking classes (QTcpSocket, QUdpSocket, QTcpServer, etc.) are asynchronous by design... [maybe, I'm not sure] " So the question is whether some of these Qt calls are not working properly because there is no event loop. So, some options might be: 1) Figure out some way of not using Qt in qt_term to access qtgnuplot1234. 2) Set up Qt properly and use the Qt functions. In addition, the signals/slots would get rid of the while loops. There are easy ways to put Qt into a sleep state (via mutex) rather than polling, etc. Dan |
From: Daniel J S. <dan...@ie...> - 2014-02-14 04:30:39
|
On 02/13/2014 05:09 AM, Yuriy Kaminskiy wrote: > sfeam wrote: >> On Wednesday, 12 February 2014 08:50:18 PM Daniel J Sebald wrote: >>> On 02/12/2014 02:49 PM, Thomas Bleher wrote: >>>> * Daniel J Sebald<dan...@ie...> [2014-02-12 06:36]: >>>>> In any case, I suggest adding the sleep as Ethan has done. There is >>>>> no reason that should be running at 100%. In fact, there is >>>>> probably a preferred way to do this without polling loops. I >>>>> learned a little bit about Qt working on Octave and Qt has this >>>>> paradigm of signals and slots and the developers suggest adhering to >>>>> the concept otherwise can get kind of dodgy (not in this simple >>>>> case...but cases where widget IDs are floating about). >>>>> >>>>> signal: something that a Qt object emits >>>>> slot: the destination of the signal which can >>>>> be of any number, e.g., five other >>>>> objects could connect a slot to a signal >>>>> >>>>> Anyhow, I don't have time to look at this right now, but if one >>>>> looks at the documentation for a Qt socket: >>>>> >>>>> http://qt-project.org/doc/qt-4.8/qlocalsocket.html#connectToServer >>>>> >>>>> it indicates that a signal is emitted when the connection is >>>>> complete and there is a signal emitted when there is an error. So >>>>> the proper thing to do is to first make connections to the socket >>>>> sort of like the following ("success" and "failed" are custom member >>>>> functions): >>>>> >>>>> connect (createdsocket, SIGNAL (connected ()), watcher, SLOT (success ())); >>>>> connect (createdsocket, SIGNAL (error ()), watcher, SLOT (failed ())); >>>>> >>>>> and then tell the socket to attempt to connect to the server: >>>>> >>>>> createdsocket->connectToServer (name) >>>>> >>>>> There is no need to check in a loop for anything. Either the socket >>>>> will successfully connect and emit "connected" at which point >>>>> "success()" will get called or the socket will timeout and emit >>>>> "error" at which point "failed()" will get called. >>>>> >>>>> One can get very creative about connections made, the number of >>>>> slots watching a signal, doing this dynamically, etc. So instead of >>>>> a recursive routine, it might be multiple connections, or >>>>> dynamically reconnect/disconnect in the "failed()" slot. Etc. >>>> signals and slots are indeed very nice, but they need a Qt event loop to >>>> work correctly. I don't think it is possible to add the Qt event loop to >>>> gnuplot without major surgery. (Well, you can start a local event loop >>>> using QEventLoop inside a function, but in this case it's just more work >>>> to get the same result we already have). >>> Good point, but we'll see if we can make it work somehow. It's worth at >>> least a couple hours time to test whether it is feasible. It would seem >>> that the place to start the Qt event loop along with setting up initial >>> signals/slots would be upon calling "term qt". The good thing is that >>> the graphics is done in the satellite Qt program. The bits accessible >>> to gnuplot core don't need graphics, so perhaps that Qt event loop could >>> be run in a different, non-main thread without too much work. >>> >>> Local event loop might work, but that seems like a lot of overhead to >>> communicate every time with a remote program with any sort of high >>> bandwidth. Local event loops are what dialog boxes can and often use. >>> Overhead isn't an issue there. >> >> I don't agree that an event loop is needed for this particular purpose. >> We don't have a case of asynchronous processes sending each other >> signals at random times. We just want some way for the daughter >> process to signal back to the parent process "I'm ready now, you can >> proceed". And we want some way for the parent to wait for this >> signal without burning CPU cycles. One would think from its name that >> QLocalSocket::waitForConnected() provides exactly this service, but >> evidently it doesn't. At least in linux it should be possible to have the >> parent call sigwait(), and the daughter call kill(parent_pid, SIGUSR1). >> No need to involve Qt in this. > > Signals is *increadibly* fragile IPC mechanism. There are very hard restriction > on what is permitted in signal handlers (that frequently violated, which result > in very hard-to-catch and nasty bugs), you can easily end up with racy code, > signals may lost, etc. I've not experienced such a thing and found, so far, Qt signals/slots fairly robust. Mutexes seem to work rather well for across thread traffic. Do you have an example of a race condition? I can't think of any hard and fast rules other than one isn't supposed to cast the object ID and use it as an object pointer because the object could be deleted. (Emitted signals are fine because any time an object is deleted, all its connections are removed along with it.) Within a thread there shouldn't be a race condition because signals are processed right away, if I remember correctly. Across thread are treated differently. They are queued. But there is where the Mutex comes into play. By temporarily suspending a worker process (typically on the order of milliseconds) and having the thread awoken when tasks are complete, race conditions are avoided. Dan |
From: Yuriy K. <yu...@gm...> - 2014-02-14 08:33:12
|
Daniel J Sebald wrote: > On 02/13/2014 05:09 AM, Yuriy Kaminskiy wrote: >> sfeam wrote: >>> On Wednesday, 12 February 2014 08:50:18 PM Daniel J Sebald wrote: >>>> On 02/12/2014 02:49 PM, Thomas Bleher wrote: >>>>> * Daniel J Sebald<dan...@ie...> [2014-02-12 06:36]: [...] >>>> Local event loop might work, but that seems like a lot of overhead to >>>> communicate every time with a remote program with any sort of high >>>> bandwidth. Local event loops are what dialog boxes can and often use. >>>> Overhead isn't an issue there. >>> I don't agree that an event loop is needed for this particular purpose. >>> We don't have a case of asynchronous processes sending each other >>> signals at random times. We just want some way for the daughter >>> process to signal back to the parent process "I'm ready now, you can >>> proceed". And we want some way for the parent to wait for this >>> signal without burning CPU cycles. One would think from its name that >>> QLocalSocket::waitForConnected() provides exactly this service, but >>> evidently it doesn't. At least in linux it should be possible to have the >>> parent call sigwait(), and the daughter call kill(parent_pid, SIGUSR1). ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >>> No need to involve Qt in this. >> Signals is *increadibly* fragile IPC mechanism. There are very hard restriction >> on what is permitted in signal handlers (that frequently violated, which result >> in very hard-to-catch and nasty bugs), you can easily end up with racy code, >> signals may lost, etc. > > I've not experienced such a thing and found, so far, Qt signals/slots > fairly robust. Mutexes seem to work rather well for across thread I refer here to "asynchronous signals" - see `man 7 signal` and `man 2 sigaction`, `man 3 sigwait`, `man 2 kill`, etc, *not* to Qt's signals/slots (I don't think they are anyhow related; besides, Qt signals are not "IPC mechanism"). > traffic. Do you have an example of a race condition? I can't think of > any hard and fast rules other than one isn't supposed to cast the object > ID and use it as an object pointer because the object could be deleted. > (Emitted signals are fine because any time an object is deleted, all > its connections are removed along with it.) > > Within a thread there shouldn't be a race condition because signals are > processed right away, if I remember correctly. Across thread are > treated differently. They are queued. But there is where the Mutex > comes into play. By temporarily suspending a worker process (typically > on the order of milliseconds) and having the thread awoken when tasks > are complete, race conditions are avoided. |
From: Jérôme L. <lod...@us...> - 2014-02-14 05:52:16
|
I agree with Ethan that an event loop should not be necessary in qt_qterm.cpp. However, if someone wants to experiment, I have already made such an attempt to integrate a Qt event loop within the gnuplot event loop in http://sourceforge.net/p/gnuplot/patches/645/ in eventloop.patch Jérôme Le mercredi 12 février 2014 20:14:19 sfeam a écrit : > I don't agree that an event loop is needed for this particular purpose. > We don't have a case of asynchronous processes sending each other > signals at random times. We just want some way for the daughter > process to signal back to the parent process "I'm ready now, you can > proceed". And we want some way for the parent to wait for this > signal without burning CPU cycles. One would think from its name that > QLocalSocket::waitForConnected() provides exactly this service, but > evidently it doesn't. At least in linux it should be possible to have the > parent call sigwait(), and the daughter call kill(parent_pid, SIGUSR1). No > need to involve Qt in this. > > Ethan |
From: Bastian M. <bma...@we...> - 2014-02-14 20:06:03
Attachments:
qt-flushout.diff
|
The workaround for a non-functional call to QLocalSocket.waitForBytesWritten in qt_flushOutBuffer seems to have a timing problem - on Windows at least. The sequence of flush and waitForBytesWritten(-1) dead locks and stalls gnuplot. This is easy to trigger when e.g. rotating 3d graphs rapidly with the mouse. Just using waitForBytesWritten(-1) directly seems to work just fine, though. This is to be also indicated by a comment ("update: seems to work with Qt 4.5.") there. The patch attached is conditional on Qt >= 4.5. Could somebody please test if that also works on Linux/Mac? Bastian Am 14.02.2014 06:52, schrieb Jérôme Lodewyck: > I agree with Ethan that an event loop should not be necessary in qt_qterm.cpp. > However, if someone wants to experiment, I have already made such an attempt > to integrate a Qt event loop within the gnuplot event loop in > http://sourceforge.net/p/gnuplot/patches/645/ > in eventloop.patch > > Jérôme > > > Le mercredi 12 février 2014 20:14:19 sfeam a écrit : >> I don't agree that an event loop is needed for this particular purpose. >> We don't have a case of asynchronous processes sending each other >> signals at random times. We just want some way for the daughter >> process to signal back to the parent process "I'm ready now, you can >> proceed". And we want some way for the parent to wait for this >> signal without burning CPU cycles. One would think from its name that >> QLocalSocket::waitForConnected() provides exactly this service, but >> evidently it doesn't. At least in linux it should be possible to have the >> parent call sigwait(), and the daughter call kill(parent_pid, SIGUSR1). No >> need to involve Qt in this. >> >> Ethan > |
From: Mojca M. <moj...@gm...> - 2014-02-14 20:35:56
|
On Fri, Feb 14, 2014 at 9:05 PM, Bastian Märkisch wrote: > The workaround for a non-functional call to QLocalSocket.waitForBytesWritten > in qt_flushOutBuffer seems to have a timing problem - on Windows at least. > > The sequence of flush and waitForBytesWritten(-1) dead locks and stalls > gnuplot. This is easy to trigger when e.g. rotating 3d graphs rapidly with > the mouse. > > Just using waitForBytesWritten(-1) directly seems to work just fine, though. > This is to be also indicated by a comment ("update: seems to work with Qt > 4.5.") there. The patch attached is conditional on Qt >= 4.5. Could somebody > please test if that also works on Linux/Mac? No, it doesn't. I get QAbstractSocket::waitForBytesWritten() is not allowed in UnconnectedState printed to the terminal and then I'm unable to do any interaction with the mouse at all. Some plots from demos are not even displayed. Mojca |
From: Bastian M. <bma...@we...> - 2014-02-15 08:37:26
|
Am 14.02.2014 21:35, schrieb Mojca Miklavec: > On Fri, Feb 14, 2014 at 9:05 PM, Bastian Märkisch wrote: >> The workaround for a non-functional call to QLocalSocket.waitForBytesWritten >> in qt_flushOutBuffer seems to have a timing problem - on Windows at least. >> >> The sequence of flush and waitForBytesWritten(-1) dead locks and stalls >> gnuplot. This is easy to trigger when e.g. rotating 3d graphs rapidly with >> the mouse. >> >> Just using waitForBytesWritten(-1) directly seems to work just fine, though. >> This is to be also indicated by a comment ("update: seems to work with Qt >> 4.5.") there. The patch attached is conditional on Qt >= 4.5. Could somebody >> please test if that also works on Linux/Mac? > > No, it doesn't. I get > QAbstractSocket::waitForBytesWritten() is not allowed in UnconnectedState > printed to the terminal and then I'm unable to do any interaction with > the mouse at all. Some plots from demos are not even displayed. > > Mojca > Thanks for the feedback. So I kept the loop but added another check for bytesToWrite > 0 which should do no harm in any case, but prevents stalling on Windows. Code is in CVS. Bastian |
From: Yuriy K. <yu...@gm...> - 2014-02-13 11:10:05
|
sfeam wrote: > On Wednesday, 12 February 2014 08:50:18 PM Daniel J Sebald wrote: >> On 02/12/2014 02:49 PM, Thomas Bleher wrote: >>> * Daniel J Sebald<dan...@ie...> [2014-02-12 06:36]: >>>> In any case, I suggest adding the sleep as Ethan has done. There is >>>> no reason that should be running at 100%. In fact, there is >>>> probably a preferred way to do this without polling loops. I >>>> learned a little bit about Qt working on Octave and Qt has this >>>> paradigm of signals and slots and the developers suggest adhering to >>>> the concept otherwise can get kind of dodgy (not in this simple >>>> case...but cases where widget IDs are floating about). >>>> >>>> signal: something that a Qt object emits >>>> slot: the destination of the signal which can >>>> be of any number, e.g., five other >>>> objects could connect a slot to a signal >>>> >>>> Anyhow, I don't have time to look at this right now, but if one >>>> looks at the documentation for a Qt socket: >>>> >>>> http://qt-project.org/doc/qt-4.8/qlocalsocket.html#connectToServer >>>> >>>> it indicates that a signal is emitted when the connection is >>>> complete and there is a signal emitted when there is an error. So >>>> the proper thing to do is to first make connections to the socket >>>> sort of like the following ("success" and "failed" are custom member >>>> functions): >>>> >>>> connect (createdsocket, SIGNAL (connected ()), watcher, SLOT (success ())); >>>> connect (createdsocket, SIGNAL (error ()), watcher, SLOT (failed ())); >>>> >>>> and then tell the socket to attempt to connect to the server: >>>> >>>> createdsocket->connectToServer (name) >>>> >>>> There is no need to check in a loop for anything. Either the socket >>>> will successfully connect and emit "connected" at which point >>>> "success()" will get called or the socket will timeout and emit >>>> "error" at which point "failed()" will get called. >>>> >>>> One can get very creative about connections made, the number of >>>> slots watching a signal, doing this dynamically, etc. So instead of >>>> a recursive routine, it might be multiple connections, or >>>> dynamically reconnect/disconnect in the "failed()" slot. Etc. >>> signals and slots are indeed very nice, but they need a Qt event loop to >>> work correctly. I don't think it is possible to add the Qt event loop to >>> gnuplot without major surgery. (Well, you can start a local event loop >>> using QEventLoop inside a function, but in this case it's just more work >>> to get the same result we already have). >> Good point, but we'll see if we can make it work somehow. It's worth at >> least a couple hours time to test whether it is feasible. It would seem >> that the place to start the Qt event loop along with setting up initial >> signals/slots would be upon calling "term qt". The good thing is that >> the graphics is done in the satellite Qt program. The bits accessible >> to gnuplot core don't need graphics, so perhaps that Qt event loop could >> be run in a different, non-main thread without too much work. >> >> Local event loop might work, but that seems like a lot of overhead to >> communicate every time with a remote program with any sort of high >> bandwidth. Local event loops are what dialog boxes can and often use. >> Overhead isn't an issue there. > > I don't agree that an event loop is needed for this particular purpose. > We don't have a case of asynchronous processes sending each other > signals at random times. We just want some way for the daughter > process to signal back to the parent process "I'm ready now, you can > proceed". And we want some way for the parent to wait for this > signal without burning CPU cycles. One would think from its name that > QLocalSocket::waitForConnected() provides exactly this service, but > evidently it doesn't. At least in linux it should be possible to have the > parent call sigwait(), and the daughter call kill(parent_pid, SIGUSR1). > No need to involve Qt in this. Signals is *increadibly* fragile IPC mechanism. There are very hard restriction on what is permitted in signal handlers (that frequently violated, which result in very hard-to-catch and nasty bugs), you can easily end up with racy code, signals may lost, etc. And kill(parent_pid,SIGUSR1) is, obviously, racy and dangerous (parent process can die before children noticed, pid can be reused, and you can kill wrong process [and default handler for SIGUSR1 terminates process!]). |
From: Daniel J S. <dan...@ie...> - 2014-02-24 03:02:49
|
I've sent some sample code to Jérôme and Mojca to test out. It isn't robust code just yet. Rather I want to see how things behave on OSX. So there is no need for the general group to look at the code just yet. If the behavior on OSX matches what I'm seeing on Linux, that is good. Why should it match? Because I moved the bulk of the qt terminal inside a separate thread where timing should work consistently for all platforms. (Now, whether Windows supports thread, I don't know... but let's just start with OSX first.) I'm saying that the thread concept is necessary, but it doesn't seem straightforward and conceptually it is nice having the terminal in a separate thread. Hopefully Jérôme can assess how the layout is and the thread idea. I tried to change as little as possible, but there were some things I had to modify a bit with regard to recursive calls back into the gnuplot core. I will follow up with a separate thread. Dan |
From: Daniel J S. <dan...@ie...> - 2014-02-24 03:31:11
|
On 02/23/2014 09:02 PM, Daniel J Sebald wrote: > let's just start with OSX first.) I'm saying that the thread concept is > necessary, but it doesn't seem straightforward and conceptually it is > nice having the terminal in a separate thread. Oy, I'm NOT saying the thread concept is necessary but it DOES seem straightforward. Dan |
From: Daniel J S. <dan...@ie...> - 2014-02-22 16:55:47
|
On 02/16/2014 05:47 PM, Daniel J Sebald wrote: > I've a good start on the separate thread for Qt. I think it is going to > work, but it will probably be next weekend until I finish. I just don't > have the time right now. So Mojca, you'll have to wait a week I guess. > > It's been pretty straightforward up to this point. I just laid things > out the way the Qt documentation shows. The separate thread starts and > now timers definitely work as expected. I have signals going across > without much problems. The external program gnuplot_qt shows up. There > are two remaining issues: > > 1) Timing. Since this is signaling into a thread rather than calling, > the signal returns right away and gnuplot core continues onward not > having valid values for settings (i.e., x, y dimensions, etc.). While > that goes on, the other thread has problems and 30 seconds later > complaints show up in qDebug(), and 30 seconds later once again, and 30 > seconds later is the last try. I know how to fix this. It just takes a > QMutex and putting it to sleep and have the object in the QThread wake > it when it has finished or timed out. I've done it before. > > 2) Reorganization. I think the number of ways connectToServer tries to > connect can be simplified, without recursion. The complaints from Qt are > along the lines of some child objects being created in a thread > different from its parent. Shouldn't be difficult to fix with some > better reorganization. I've already broken the Qt class declarations > into individual files QtTerminalEmitter.h (same main thread as gnuplot) > and QtTerminalInterface.h (separate thread), which is similar to the > rest of the Qt code in the qtterminal directory. > > More next weekend or later in the week. Things are slowly coming along, but I've become rather busy with a number of projects at work. I would like to point out that I have a new way of waiting for the gnuplot_qt server to be active that avoids that clumsy while loop. Here's a brief summary if Ethan wants to try and tweak the CVS repository. Otherwise, what I will have is a fairly big diff file in the coming week. It's fairly simple, really. But first, I'd like to ask if it is alright to create the process not as detached, but just a normal process. Is that OK? If that is done, then after starting the QProcess that will create the local server, just wait for the process to write back the server's name and continue onward. By writing the local server name to standard output (fprint/fflush) when everything is set up and ready to go, the first time that qt_term attempts to connect to the local server will be a success. IN QT_TERM.CPP: if (!qtgnuplotProcess) qtgnuplotProcess = new QProcess(); qtgnuplotProcess->start(filename, QStringList()); if (qtgnuplotProcess->waitForStarted()) { qtgnuplotProcess->waitForReadyRead(); localServerName = qtgnuplotProcess->readAllStandardOutput(); qDebug() << localServerName; } else { qDebug() << "QProcess starting failed:" << qtgnuplotProcess->errorString(); } IN QTGNUPLOTAPPLICATION.CPP: QtGnuplotApplication::QtGnuplotApplication(int& argc, char** argv) : QApplication(argc, argv) { ... connect(m_eventHandler, SIGNAL(disconnected()), this, SLOT(enterPersistMode())); fprintf(stdout, sName.toLocal8Bit().data()); fflush(stdout); } Dan |
From: Mojca M. <moj...@gm...> - 2014-02-12 21:01:46
|
On Mon, Feb 10, 2014 at 1:57 AM, sfeam wrote: > On Sunday, 09 February 2014 12:29:34 PM Mojca Miklavec wrote: ... >> Total number in stack (recursive counted multiple, when >=5): >> >> Sort by top of stack, same collapsed (when >= 5): >> __select (in libsystem_kernel.dylib) 2510 >> kevent (in libsystem_kernel.dylib) 2510 >> QIODevice::bytesAvailable() const (in QtCore) 941 >> qt_sendFont() (in gnuplot) 379 >> QAbstractSocket::bytesAvailable() const (in QtNetwork) 248 >> QLocalSocket::bytesAvailable() const (in QtNetwork) 236 >> QLocalSocket::waitForReadyRead(int) (in QtNetwork) 195 >> DYLD-STUB$$QIODevice::bytesAvailable() const (in QtNetwork) 157 >> QLocalSocket::state() const (in QtNetwork) 147 >> DYLD-STUB$$QLocalSocket::waitForReadyRead(int) (in gnuplot) 110 >> DYLD-STUB$$QLocalSocket::bytesAvailable() const (in gnuplot) 97 >> >> Mojca > > Finally a trace that makes sense in that it involves a recent change. > This bit belongs to the patch: > > 2014-01-26 Jérôme Lodewyck <lod...@us...> > > * src/qtterminal/qt_term.cpp: Implement font metric caching. This solves > a flickering issue when a large number of font changes are called (for > example when rotating the world plot in world2.dem). > > * src/qtterminal/QtGnuplotInstance.*: New public function that sends a > command to gnuplot and blocks until it receives the answer. > > Can you back out just that one set of changes from current CVS and see > if that makes your qt terminal work? I don't know if it makes much sense to debug infinite loops when it's clear that the loops happened when gnuplot wasn't even connected properly/initialized at startup (the code was executed with badly initialized gnuplot under assumption that connection was successful). But if I revert that patch alone, the first plot still doesn't work properly. However if I revert the following commit from 2014-01-29 Jérôme Lodewyck Postpone show() in QtGnuplotWindow then the first plot displays just fine and then basically everything works as expected. Mojca |
From: sfeam <sf...@us...> - 2014-02-13 04:54:19
Attachments:
qt_term_OSX_first_time.patch
|
On Wednesday, 12 February 2014 10:01:39 PM Mojca Miklavec wrote: > > However if I revert the following commit from > 2014-01-29 Jérôme Lodewyck Postpone show() in QtGnuplotWindow > then the first plot displays just fine and then basically everything > works as expected. > Mojca Based on this and our off-line back and forth debugging, I am pretty sure that the attached patch will fix your problem that the first plot is not drawn. It is, as you say, a partial reversion of the 2014-01-29 patch. I have made it conditional on #ifdef __APPLE__ but see below. Jérôme: On Mojca's machine the viewport size always seems to be equal to the window size on entry. This means that the resize is not performed the first time in the existing code. Couldn't this happen on linux too? Ethan |
From: Mojca M. <moj...@gm...> - 2014-02-13 10:23:22
|
Just another observation before I test further: it wasn't just a problem of first-time plot. It was also *sometimes* a problem of the first plot after closing the plotting window. But that was semi-random. Sometimes it worked and sometimes it didn't. This could have been related to whether a new plot was a different one or not or maybe related to timing. I would say that it's a problem that if (!parent->isVisible()) is hidden inside if (s != viewport->size()) because the reverse can be true: c may well be equal to viewport->size(), but parent may not be visible. I don't know the code well enough, but it looks like parent is not visible whenever I close the plotting window (or during the initial plot). Mojca |
From: Jérôme L. <lod...@us...> - 2014-02-13 11:13:16
Attachments:
show.patch
|
Here is a patch that applies on top of CVS. You are right : showing the window should be done regardless on whether the size has changed or not. Jérôme Le 13/02/2014 11:23, Mojca Miklavec a écrit : > Just another observation before I test further: it wasn't just a > problem of first-time plot. It was also *sometimes* a problem of the > first plot after closing the plotting window. But that was > semi-random. Sometimes it worked and sometimes it didn't. This could > have been related to whether a new plot was a different one or not or > maybe related to timing. > > I would say that it's a problem that > if (!parent->isVisible()) > is hidden inside > if (s != viewport->size()) > because the reverse can be true: c may well be equal to > viewport->size(), but parent may not be visible. I don't know the code > well enough, but it looks like parent is not visible whenever I close > the plotting window (or during the initial plot). > > Mojca > |
From: Mojca M. <moj...@gm...> - 2014-02-13 11:02:05
|
On Thu, Feb 13, 2014 at 11:56 AM, Jérôme Lodewyck wrote: > Here is a patch that applies on top of CVS. But it doesn't work properly. Now the window is shown, but it has the wrong size to start with (it shows just the top left corner of the plot). Mojca |