<div dir="ltr"><div>This error occurs because the guider changes state while capture is executing waitForFinished() waiting for the solver.</div>I don't understand how to set that up in TestEkosCaptureWorkflow, and would prefer if you (Wolfgang) took that on.<div><br></div><div>In general, I don't really understand the intricacies of capture.cpp and am uncomfortable making broad changes there.</div><div>I have sent in an MR to try and fix the bug I described, but not the general problem.</div><div><a href="https://invent.kde.org/education/kstars/-/merge_requests/387">https://invent.kde.org/education/kstars/-/merge_requests/387</a><br></div><div>Please check out that MR carefully. </div><div><br></div><div>Also, I did do a survey and found ~180 references to 'activeJob->' in capture.cpp<br></div><div><div><br></div><div>I looked closer and saw that most were protected references, eg. with something like </div><div>   if (activeJob == nullptr)<br>        return;<br></div><div>at the start of a method, and if there is no real parallel processing going on, and no calls to wait... then this kind of protection should be effective.</div><div><br></div><div>There are many methods with unprotected access of activeJob, though:</div><div><br></div><div>setCaptureComplete<br></div><div>checkDithering<br>processJobCompletionStage1<br>processJobCompletionStage2<br>prepareActiveJobStage1<br>prepareActiveJobStage2<br>preparePreCaptureActions<br>updatePrepareState<br>executeJob<br>setCurrentADU<br>checkLightFrameScopeCoverOpen<br>checkDarkFramePendingTasks<br>checkFlatFramePendingTasks<br>processPostCaptureCalibrationStage<br>scriptFinished<br></div><div><br></div><div>It seems likely that some/all of these should also add tests for activeJob == nullptr</div><div><br></div><div>Hy</div><div><br></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Aug 13, 2021 at 12:55 PM Wolfgang Reissenberger <<a href="mailto:sterne-jaeger@openfuture.de" target="_blank">sterne-jaeger@openfuture.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">What about general avoiding a null value here?<br>
<br>
> Am 13.08.2021 um 18:04 schrieb Jasem Mutlaq <<a href="mailto:mutlaqja@ikarustech.com" target="_blank">mutlaqja@ikarustech.com</a>>:<br>
> <br>
> I agree with Wolfgang that we need a better solution for this issue.<br>
> For the time being, checking if activeJob is null is the way to<br>
> resolve it.<br>
> <br>
> --<br>
> Best Regards,<br>
> Jasem Mutlaq<br>
> <br>
> <br>
> On Fri, Aug 13, 2021 at 4:54 PM Wolfgang Reissenberger<br>
> <<a href="mailto:sterne-jaeger@openfuture.de" target="_blank">sterne-jaeger@openfuture.de</a>> wrote:<br>
>> <br>
>> Hm, tricky, this looks like a problem that we need to solve more generally. Obviously, using one simple pointer for the active job is not thread safe. In Java, I would solve this with a accessor function that throws a specific exception, that can be caught in a central place. But I’m not sure what the appropriate answer in C++ is...<br>
>> <br>
>> But anyway, let’s start developing a solution for it like we did it with all the other edge cases: step 1 is to develop a test case that (more or less) makes this problem reproducible. A good starting point could be extending  TestEkosCaptureWorkflow, which I created a couple of weeks ago.<br>
>> <br>
>> Hy, could you give it a try? I could assist…<br>
>> <br>
>> Wolfgang<br>
>> <br>
>> Am 13.08.2021 um 06:02 schrieb Hy Murveit <<a href="mailto:murveit@gmail.com" target="_blank">murveit@gmail.com</a>>:<br>
>> <br>
>> TL;DR<br>
>> <br>
>> I got a segv in bad weather the other night.<br>
>> I did trace down what caused it, see below, but I think I should leave the solution to someone more experienced in the intricacies of capture (e.g. Wolfgang or Jasem).<br>
>> <br>
>> Why it crashed:<br>
>> <br>
>> You can see the end of the log below (log stops on segv after these 20 lines).<br>
>> You can also see the backtrace below it.<br>
>> <br>
>> Bottom line, it's clear from the gdb backtrace that it dies in Capture::setCaptureComplete(), and I believe it died trying to reference the activeJob variable<br>
>> which is set to nullptr because of Guiding state changed from "Reacquiring" to "Aborted.<br>
>> <br>
>> When the guiding state changed from  "Reacquiring" to "Aborted" in setGuideStatus().<br>
>> - it called processGuidingFailed(),<br>
>> - which called abort()<br>
>> - which called stop()<br>
>> - which sets activeJob = nullptr.<br>
>> <br>
>> Meanwhile, while all that was happening, setCaptureComplete was waiting for the solver to run:<br>
>>            QFuture<bool> result = m_ImageData->findStars(ALGORITHM_SEP);<br>
>>            result.waitForFinished();<br>
>> <br>
>> and while it was waiting, activeJob was set to nullptr but the guiding status change.  So, after the wait completed, setCaptureComplete<br>
>> probably failed onemit captureComplete(filename, activeJob->getFilterName(), ...)<br>
>> or perhaps below that on "if (activeJob->getCount())"<br>
>> because activeJob is now nullptr.<br>
>> <br>
>> Solution:<br>
>> <br>
>> We could simply protect the access of activeJob by testing if it's not null.<br>
>> That would certainly work for the emit captureComplete (just don't emit it if guiding has failed).<br>
>> <br>
>> However, I'm not sure what to do about the second access.<br>
>> Should it just do this both places?<br>
>> <br>
>> if (activeJob == nullptr) return IPS_OK;<br>
>> <br>
>> Anyway, I'll leave this for Jasem and/or Wolfgang.<br>
>> <br>
>> Hy<br>
>> <br>
>> <br>
>> <br>
>> [2021-08-12T02:28:23.284 PDT INFO ][   org.kde.kstars.ekos.capture] - "Received image 16 out of 60."<br>
>> [2021-08-12T02:28:23.286 PDT DEBG ][           org.kde.kstars.fits] - Sextract with:  "1-HFR-Default"<br>
>> [2021-08-12T02:28:23.580 PDT DEBG ][           org.kde.kstars.indi] - Image received. Mode: "Guide" Size: 313920<br>
>> [2021-08-12T02:28:23.581 PDT DEBG ][           org.kde.kstars.fits] - Reading file buffer ( "306.6 KiB" )<br>
>> [2021-08-12T02:28:23.614 PDT DEBG ][     org.kde.kstars.ekos.guide] - Received guide frame.<br>
>> [2021-08-12T02:28:23.614 PDT DEBG ][     org.kde.kstars.ekos.guide] - Multistar: findTopStars 10<br>
>> [2021-08-12T02:28:23.615 PDT DEBG ][           org.kde.kstars.fits] - Sextract with:  "1-Guide-Default"<br>
>> [2021-08-12T02:28:23.679 PDT DEBG ][           org.kde.kstars.indi] - Rainbow Astro RSF : "[DEBUG] CMD <:Fp#> "<br>
>> [2021-08-12T02:28:23.679 PDT DEBG ][           org.kde.kstars.indi] - Rainbow Astro RSF : "[DEBUG] RES <:FP-04.815#> "<br>
>> [2021-08-12T02:28:23.700 PDT DEBG ][ org.kde.kstars.ekos.scheduler] - Scheduler iteration never set up.<br>
>> [2021-08-12T02:28:23.708 PDT DEBG ][     org.kde.kstars.ekos.guide] - "Select      #   x      y      flux    HFR  SNR   score"<br>
>> [2021-08-12T02:28:23.708 PDT DEBG ][     org.kde.kstars.ekos.guide] - No suitable star detected.<br>
>> [2021-08-12T02:28:23.708 PDT INFO ][     org.kde.kstars.ekos.guide] - "Failed to find any suitable guide stars. Aborting..."<br>
>> [2021-08-12T02:28:23.709 PDT DEBG ][   org.kde.kstars.ekos.capture] - Guiding state changed from "Reacquiring" to "Aborted"<br>
>> [2021-08-12T02:28:23.710 PDT INFO ][   org.kde.kstars.ekos.capture] - "Autoguiding stopped. Aborting..."<br>
>> [2021-08-12T02:28:23.768 PDT INFO ][   org.kde.kstars.ekos.capture] - "CCD capture aborted"<br>
>> [2021-08-12T02:28:23.770 PDT DEBG ][     org.kde.kstars.ekos.guide] - Reset non guiding dithering position<br>
>> [2021-08-12T02:28:23.771 PDT DEBG ][   org.kde.kstars.ekos.capture] - setMeridianFlipStage:  "MF_READY"<br>
>> [2021-08-12T02:28:23.837 PDT INFO ][     org.kde.kstars.ekos.guide] - "Autoguiding aborted."<br>
>> [2021-08-12T02:28:23.837 PDT DEBG ][     org.kde.kstars.ekos.guide] - Aborting "Reacquiring"<br>
>>> <br>
>> <br>
>> <br>
>> <br>
>> <br>
>> (gdb) bt<br>
>> #0  0x0000aaaaaafcfe64 in Ekos::Capture::b() (this=this@entry=0xaaaab68c02b0)<br>
>>    at /home/hy/Projects/kstars/kstars/ekos/capture/sequencejob.h:153<br>
>> #1  0x0000aaaaaafd0b70 in Ekos::Capture::processData(QSharedPointer<FITSData> const&) (this=0xaaaab68c02b0, data=...)<br>
>>    at /home/hy/Projects/kstars/kstars/ekos/capture/capture.cpp:1700<br>
>> #2  0x0000fffff5416d5c in  () at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #3  0x0000aaaaaaddbe68 in ISD::CCD::newImage(QSharedPointer<FITSData> const&) (this=this@entry=0xaaaaafe245c0, _t1=...)<br>
>>    at /home/hy/Projects/kstars-build/kstars/KStarsLib_autogen/FRI4DANIHA/moc_indiccd.cpp:413<br>
>> #4  0x0000aaaaaaea668c in ISD::CCD::handleImage(ISD::CCDChip*, QString const&, _IBLOB*, QSharedPointer<FITSData>)<br>
>>    (this=this@entry=0xaaaaafe245c0, targetChip=targetChip@entry=0xaaaab1a8dca0, filename=..., bp=bp@entry=0xffff94014950, data=...) at /home/hy/Projects/kstars/kstars/indi/indiccd.cpp:1699<br>
>> #5  0x0000aaaaaaead8d0 in ISD::CCD::processBLOB(_IBLOB*) (this=0xaaaaafe245c0, bp=0xffff94014950)<br>
>>    at /usr/include/c++/10/bits/atomic_base.h:325<br>
>> #6  0x0000fffff5416d5c in  () at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #7  0x0000aaaaaaddd1cc in ClientManager::newINDIBLOB(_IBLOB*) (this=<optimized out>, _t1=<optimized out>)<br>
>>    at /home/hy/Projects/kstars-build/kstars/KStarsLib_autogen/FRI4DANIHA/moc_clientmanager.cpp:369<br>
>> #8  0x0000fffff540cbfc in QObject::event(QEvent*) () at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #9  0x0000fffff5e1a480 in QApplicationPrivate::notify_helper(QObject*, QEvent*) ()<br>
>>    at /lib/aarch64-linux-gnu/libQt5Widgets.so.5<br>
>> #10 0x0000fffff53dc56c in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #11 0x0000fffff53df2c8 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) ()<br>
>>    at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #12 0x0000fffff543ae68 in  () at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #13 0x0000fffff4410c30 in g_main_context_dispatch () at /lib/aarch64-linux-gnu/libglib-2.0.so.0<br>
>> #14 0x0000fffff4410ec8 in  () at /lib/aarch64-linux-gnu/libglib-2.0.so.0<br>
>> #15 0x0000fffff4410f94 in g_main_context_iteration () at /lib/aarch64-linux-gnu/libglib-2.0.so.0<br>
>> #16 0x0000fffff543a304 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) ()<br>
>>    at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #17 0x0000fffff53da97c in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) ()<br>
>>    at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #18 0x0000fffff53e3a7c in QCoreApplication::exec() () at /lib/aarch64-linux-gnu/libQt5Core.so.5<br>
>> #19 0x0000aaaaaab9956c in main(int, char**) (argc=<optimized out>, argv=<optimized out>)<br>
>>    at /home/hy/Projects/kstars/kstars/main.cpp:393<br>
>> (gdb)<br>
>> <br>
>> <br>
>> <br>
>> <br>
<br>
</blockquote></div>