[libcamera-devel] [PATCH] android: camera_worker: Process all queued requests when stopping
Jacopo Mondi
jacopo at jmondi.org
Mon May 24 14:05:29 CEST 2021
Hi Laurent,
On Mon, May 24, 2021 at 02:50:21PM +0300, Laurent Pinchart wrote:
> Hi Jacopo,
>
> On Mon, May 24, 2021 at 11:33:10AM +0200, Jacopo Mondi wrote:
> > On Sun, May 23, 2021 at 05:33:42AM +0300, Laurent Pinchart wrote:
> > > When stopping the camera worker, queuedRequest() calls may have queued
> > > asynchronous function invocation messages to the worker thread, and some
> > > of those messages may not have been processed yet. The messages will
> > > stay in the thread's queue until the camera worker is restarted (when
> > > the camera service will start a new capture session). At that point,
> > > they will be dispatched, which will cause a crash due to the
> > > CaptureRequest passed to processRequest() having been deleted by
> > > CameraDevice::stop() calling descriptors_.clear().
> > >
> > > Fix this by forcing dispatching of all function invocation messages when
> > > stopping the camera worker thread. Note that this is inherently racy, as
> > > more queueRequest() calls may arrive from the camera service while we're
> > > stopping. This race condition will be addressed by a subsequent patch
> > > series.
> > >
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > > ---
> > > I haven't tested this patch, as I'm currently rebuilding a new Soraka
> > > image. Hiro, could you give it a try to see if it fixes the problem
> > > you've reported ?
> > > ---
> > > src/android/camera_worker.cpp | 14 ++++++++++----
> > > src/android/camera_worker.h | 6 ++++--
> > > 2 files changed, 14 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/src/android/camera_worker.cpp b/src/android/camera_worker.cpp
> > > index 300ddde03645..9f727826e23f 100644
> > > --- a/src/android/camera_worker.cpp
> > > +++ b/src/android/camera_worker.cpp
> > > @@ -52,18 +52,24 @@ void CaptureRequest::queue()
> > > */
> > > CameraWorker::CameraWorker()
> > > {
> > > - worker_.moveToThread(&thread_);
> > > + worker_.moveToThread(this);
Thanks for the explanation. This
moveToThread(this);
mislead me, but with the below explanation is all good now
Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>
Thanks
j
> > > }
> > >
> > > void CameraWorker::start()
> > > {
> > > - thread_.start();
> > > + Thread::start();
> > > }
> > >
> > > void CameraWorker::stop()
> > > {
> > > - thread_.exit();
> > > - thread_.wait();
> > > + exit();
> > > + wait();
> > > +}
> > > +
> > > +void CameraWorker::run()
> > > +{
> > > + exec();
> > > + dispatchMessages(Message::Type::InvokeMessage);
> > > }
> > >
> > > void CameraWorker::queueRequest(CaptureRequest *request)
> > > diff --git a/src/android/camera_worker.h b/src/android/camera_worker.h
> > > index 64b1658b61b4..e289ef9b8655 100644
> > > --- a/src/android/camera_worker.h
> > > +++ b/src/android/camera_worker.h
> > > @@ -42,7 +42,7 @@ private:
> > > std::unique_ptr<libcamera::Request> request_;
> > > };
> > >
> > > -class CameraWorker
> > > +class CameraWorker : private libcamera::Thread
> >
> > There is one thing I don't get here
> >
> > Now the whole CameraWorker runs in it own thread.
> >
> > Before this change CameraWorker had a Worker that was run a separate
> > thread.
> >
> > CameraDevice calls CameraWorker::queueRequest, which runs on a
> > different thread.
>
> While the CameraWorker instance inherits from Thread, it isn't bound the
> its own thread. The CameraWorker instance is an Object (as Thread
> inherits from Object), and Object instance are bound by default to the
> thread in which they're created. The can then be moved to another thread
> by Object::moveToThread(). In this case, the CameraWorker instance is
> created in the camera service thread (the main thread from the HAL's
> point of view), and isn't moved to any other thread with moveToThread().
> It thus stays bound to the camera service thread, not to the Thread
> instance that it inherits from.
>
> > CameraWorker::queueRequest
> >
> > void CameraWorker::queueRequest(CaptureRequest *request)
>
> In any case, functions that are called directly still run in the thread
> of the caller, in all cases. Only functions invoked through
> Object::invokeMethod() or through signals with a queued connection type
> will run in the thread to which the object is bound. This function is
> called directly by the CameraDevice, so it runs in the caller's thread.
>
> > {
> > /* Async process the request on the worker which runs its own thread. */
> > worker_.invokeMethod(&Worker::processRequest, ConnectionTypeQueued,
> > request);
>
> This invokes the Worker::processRequest() function with a queued
> connection type. As the Worker instance has been moved to the
> CameraWorker Thread, the call will be asynchronous and cross-threads.
>
> > }
> >
> > 1) How does direct method calls on CameraWorker work now that it's a
> > Thread
> > 2) If 1) is ok, then queueRequest should not need to call invokeMethod
> > on worker_ as it runs in the same thread CameraWorker itself.
> >
> > Would it be possible to keep CameraWorker a simple class and make
> > Worker a thread ?
>
> I think we could do that, and move Worker to itself with
> moveToThread(this). The Worker would then need to reimplement run() as
> done above. Moving an object to "itself's thread" hasn't been well
> tested though. Additionally, I think it's better conceptually speaking
> to have CameraWorker inheriting from Thread. You can imagine it as
> CameraWorker being a Thread, exposing an API to the CameraDevice to
> control it, with the Worker running inside that thread.
>
> > > {
> > > public:
> > > CameraWorker();
> > > @@ -52,6 +52,9 @@ public:
> > >
> > > void queueRequest(CaptureRequest *request);
> > >
> > > +protected:
> > > + void run() override;
> > > +
> > > private:
> > > class Worker : public libcamera::Object
> > > {
> > > @@ -63,7 +66,6 @@ private:
> > > };
> > >
> > > Worker worker_;
> > > - libcamera::Thread thread_;
> > > };
> > >
> > > #endif /* __ANDROID_CAMERA_WORKER_H__ */
>
> --
> Regards,
>
> Laurent Pinchart
More information about the libcamera-devel
mailing list