libcamera: camera: Centralize state checks in Private class

Move all accesses to the state_ and disconnected_ members to functions
of the Private class. This will make it easier to implement
synchronization, and simplifies the Camera class implementation.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
Laurent Pinchart 2020-01-20 00:09:23 +02:00
parent a4be7bb5ff
commit 7aeff19555
2 changed files with 90 additions and 73 deletions

View file

@ -266,15 +266,21 @@ public:
Private(PipelineHandler *pipe, const std::string &name, Private(PipelineHandler *pipe, const std::string &name,
const std::set<Stream *> &streams); const std::set<Stream *> &streams);
~Private();
bool stateBetween(State low, State high) const; int isAccessAllowed(State state, bool allowDisconnected = false) const;
bool stateIs(State state) const; int isAccessAllowed(State low, State high,
bool allowDisconnected = false) const;
void disconnect();
void setState(State state);
std::shared_ptr<PipelineHandler> pipe_; std::shared_ptr<PipelineHandler> pipe_;
std::string name_; std::string name_;
std::set<Stream *> streams_; std::set<Stream *> streams_;
std::set<Stream *> activeStreams_; std::set<Stream *> activeStreams_;
private:
bool disconnected_; bool disconnected_;
State state_; State state_;
}; };
@ -286,6 +292,12 @@ Camera::Private::Private(PipelineHandler *pipe, const std::string &name,
{ {
} }
Camera::Private::~Private()
{
if (state_ != Private::CameraAvailable)
LOG(Camera, Error) << "Removing camera while still in use";
}
static const char *const camera_state_names[] = { static const char *const camera_state_names[] = {
"Available", "Available",
"Acquired", "Acquired",
@ -293,10 +305,31 @@ static const char *const camera_state_names[] = {
"Running", "Running",
}; };
bool Camera::Private::stateBetween(State low, State high) const int Camera::Private::isAccessAllowed(State state, bool allowDisconnected) const
{ {
if (!allowDisconnected && disconnected_)
return -ENODEV;
if (state_ == state)
return 0;
ASSERT(static_cast<unsigned int>(state) < ARRAY_SIZE(camera_state_names));
LOG(Camera, Debug) << "Camera in " << camera_state_names[state_]
<< " state trying operation requiring state "
<< camera_state_names[state];
return -EACCES;
}
int Camera::Private::isAccessAllowed(State low, State high,
bool allowDisconnected) const
{
if (!allowDisconnected && disconnected_)
return -ENODEV;
if (state_ >= low && state_ <= high) if (state_ >= low && state_ <= high)
return true; return 0;
ASSERT(static_cast<unsigned int>(low) < ARRAY_SIZE(camera_state_names) && ASSERT(static_cast<unsigned int>(low) < ARRAY_SIZE(camera_state_names) &&
static_cast<unsigned int>(high) < ARRAY_SIZE(camera_state_names)); static_cast<unsigned int>(high) < ARRAY_SIZE(camera_state_names));
@ -306,21 +339,20 @@ bool Camera::Private::stateBetween(State low, State high) const
<< camera_state_names[low] << " and " << camera_state_names[low] << " and "
<< camera_state_names[high]; << camera_state_names[high];
return false; return -EACCES;
} }
bool Camera::Private::stateIs(State state) const void Camera::Private::disconnect()
{ {
if (state_ == state) if (state_ == Private::CameraRunning)
return true; state_ = Private::CameraConfigured;
ASSERT(static_cast<unsigned int>(state) < ARRAY_SIZE(camera_state_names)); disconnected_ = true;
}
LOG(Camera, Debug) << "Camera in " << camera_state_names[state_] void Camera::Private::setState(State state)
<< " state trying operation requiring state " {
<< camera_state_names[state]; state_ = state;
return false;
} }
/** /**
@ -468,8 +500,6 @@ Camera::Camera(PipelineHandler *pipe, const std::string &name,
Camera::~Camera() Camera::~Camera()
{ {
if (!p_->stateIs(Private::CameraAvailable))
LOG(Camera, Error) << "Removing camera while still in use";
} }
/** /**
@ -488,23 +518,16 @@ void Camera::disconnect()
{ {
LOG(Camera, Debug) << "Disconnecting camera " << name(); LOG(Camera, Debug) << "Disconnecting camera " << name();
/* p_->disconnect();
* If the camera was running when the hardware was removed force the
* state to Configured state to allow applications to free resources
* and call release() before deleting the camera.
*/
if (p_->state_ == Private::CameraRunning)
p_->state_ = Private::CameraConfigured;
p_->disconnected_ = true;
disconnected.emit(this); disconnected.emit(this);
} }
int Camera::exportFrameBuffers(Stream *stream, int Camera::exportFrameBuffers(Stream *stream,
std::vector<std::unique_ptr<FrameBuffer>> *buffers) std::vector<std::unique_ptr<FrameBuffer>> *buffers)
{ {
if (!p_->stateIs(Private::CameraConfigured)) int ret = p_->isAccessAllowed(Private::CameraConfigured);
return -EACCES; if (ret < 0)
return ret;
if (streams().find(stream) == streams().end()) if (streams().find(stream) == streams().end())
return -EINVAL; return -EINVAL;
@ -517,8 +540,9 @@ int Camera::exportFrameBuffers(Stream *stream,
int Camera::freeFrameBuffers(Stream *stream) int Camera::freeFrameBuffers(Stream *stream)
{ {
if (!p_->stateIs(Private::CameraConfigured)) int ret = p_->isAccessAllowed(Private::CameraConfigured, true);
return -EACCES; if (ret < 0)
return ret;
p_->pipe_->freeFrameBuffers(this, stream); p_->pipe_->freeFrameBuffers(this, stream);
@ -550,11 +574,9 @@ int Camera::freeFrameBuffers(Stream *stream)
*/ */
int Camera::acquire() int Camera::acquire()
{ {
if (p_->disconnected_) int ret = p_->isAccessAllowed(Private::CameraAvailable);
return -ENODEV; if (ret < 0)
return ret == -EACCES ? -EBUSY : ret;
if (!p_->stateIs(Private::CameraAvailable))
return -EBUSY;
if (!p_->pipe_->lock()) { if (!p_->pipe_->lock()) {
LOG(Camera, Info) LOG(Camera, Info)
@ -562,7 +584,7 @@ int Camera::acquire()
return -EBUSY; return -EBUSY;
} }
p_->state_ = Private::CameraAcquired; p_->setState(Private::CameraAcquired);
return 0; return 0;
} }
@ -580,9 +602,10 @@ int Camera::acquire()
*/ */
int Camera::release() int Camera::release()
{ {
if (!p_->stateBetween(Private::CameraAvailable, int ret = p_->isAccessAllowed(Private::CameraAvailable,
Private::CameraConfigured)) Private::CameraConfigured, true);
return -EBUSY; if (ret < 0)
return ret == -EACCES ? -EBUSY : ret;
if (allocator_) { if (allocator_) {
/* /*
@ -596,7 +619,7 @@ int Camera::release()
p_->pipe_->unlock(); p_->pipe_->unlock();
p_->state_ = Private::CameraAvailable; p_->setState(Private::CameraAvailable);
return 0; return 0;
} }
@ -643,7 +666,12 @@ const std::set<Stream *> &Camera::streams() const
*/ */
std::unique_ptr<CameraConfiguration> Camera::generateConfiguration(const StreamRoles &roles) std::unique_ptr<CameraConfiguration> Camera::generateConfiguration(const StreamRoles &roles)
{ {
if (p_->disconnected_ || roles.size() > streams().size()) int ret = p_->isAccessAllowed(Private::CameraAvailable,
Private::CameraRunning);
if (ret < 0)
return nullptr;
if (roles.size() > streams().size())
return nullptr; return nullptr;
CameraConfiguration *config = p_->pipe_->generateConfiguration(this, roles); CameraConfiguration *config = p_->pipe_->generateConfiguration(this, roles);
@ -694,14 +722,10 @@ std::unique_ptr<CameraConfiguration> Camera::generateConfiguration(const StreamR
*/ */
int Camera::configure(CameraConfiguration *config) int Camera::configure(CameraConfiguration *config)
{ {
int ret; int ret = p_->isAccessAllowed(Private::CameraAcquired,
Private::CameraConfigured);
if (p_->disconnected_) if (ret < 0)
return -ENODEV; return ret;
if (!p_->stateBetween(Private::CameraAcquired,
Private::CameraConfigured))
return -EACCES;
if (allocator_ && allocator_->allocated()) { if (allocator_ && allocator_->allocated()) {
LOG(Camera, Error) LOG(Camera, Error)
@ -740,7 +764,7 @@ int Camera::configure(CameraConfiguration *config)
p_->activeStreams_.insert(stream); p_->activeStreams_.insert(stream);
} }
p_->state_ = Private::CameraConfigured; p_->setState(Private::CameraConfigured);
return 0; return 0;
} }
@ -767,9 +791,9 @@ int Camera::configure(CameraConfiguration *config)
*/ */
Request *Camera::createRequest(uint64_t cookie) Request *Camera::createRequest(uint64_t cookie)
{ {
if (p_->disconnected_ || int ret = p_->isAccessAllowed(Private::CameraConfigured,
!p_->stateBetween(Private::CameraConfigured, Private::CameraRunning);
Private::CameraRunning)) if (ret < 0)
return nullptr; return nullptr;
return new Request(this, cookie); return new Request(this, cookie);
@ -799,11 +823,9 @@ Request *Camera::createRequest(uint64_t cookie)
*/ */
int Camera::queueRequest(Request *request) int Camera::queueRequest(Request *request)
{ {
if (p_->disconnected_) int ret = p_->isAccessAllowed(Private::CameraRunning);
return -ENODEV; if (ret < 0)
return ret;
if (!p_->stateIs(Private::CameraRunning))
return -EACCES;
if (request->buffers().empty()) { if (request->buffers().empty()) {
LOG(Camera, Error) << "Request contains no buffers"; LOG(Camera, Error) << "Request contains no buffers";
@ -837,11 +859,9 @@ int Camera::queueRequest(Request *request)
*/ */
int Camera::start() int Camera::start()
{ {
if (p_->disconnected_) int ret = p_->isAccessAllowed(Private::CameraConfigured);
return -ENODEV; if (ret < 0)
return ret;
if (!p_->stateIs(Private::CameraConfigured))
return -EACCES;
LOG(Camera, Debug) << "Starting capture"; LOG(Camera, Debug) << "Starting capture";
@ -852,11 +872,11 @@ int Camera::start()
p_->pipe_->importFrameBuffers(this, stream); p_->pipe_->importFrameBuffers(this, stream);
} }
int ret = p_->pipe_->start(this); ret = p_->pipe_->start(this);
if (ret) if (ret)
return ret; return ret;
p_->state_ = Private::CameraRunning; p_->setState(Private::CameraRunning);
return 0; return 0;
} }
@ -875,15 +895,13 @@ int Camera::start()
*/ */
int Camera::stop() int Camera::stop()
{ {
if (p_->disconnected_) int ret = p_->isAccessAllowed(Private::CameraRunning);
return -ENODEV; if (ret < 0)
return ret;
if (!p_->stateIs(Private::CameraRunning))
return -EACCES;
LOG(Camera, Debug) << "Stopping capture"; LOG(Camera, Debug) << "Stopping capture";
p_->state_ = Private::CameraConfigured; p_->setState(Private::CameraConfigured);
p_->pipe_->stop(this); p_->pipe_->stop(this);

View file

@ -314,7 +314,7 @@ const ControlInfoMap &PipelineHandler::controls(Camera *camera)
* exportFrameBuffers() and importFrameBuffers() for the streams contained in * exportFrameBuffers() and importFrameBuffers() for the streams contained in
* any camera configuration. * any camera configuration.
* *
* The only intended caller is the FrameBufferAllocator helper. * The only intended caller is Camera::exportFrameBuffers().
* *
* \return The number of allocated buffers on success or a negative error code * \return The number of allocated buffers on success or a negative error code
* otherwise * otherwise
@ -358,8 +358,7 @@ const ControlInfoMap &PipelineHandler::controls(Camera *camera)
* called only after a successful call to either of these two methods, and only * called only after a successful call to either of these two methods, and only
* once per stream. * once per stream.
* *
* The only intended callers are Camera::stop() and the FrameBufferAllocator * The only intended callers are Camera::stop() and Camera::freeFrameBuffers().
* helper.
*/ */
/** /**