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,
const std::set<Stream *> &streams);
~Private();
bool stateBetween(State low, State high) const;
bool stateIs(State state) const;
int isAccessAllowed(State state, bool allowDisconnected = false) const;
int isAccessAllowed(State low, State high,
bool allowDisconnected = false) const;
void disconnect();
void setState(State state);
std::shared_ptr<PipelineHandler> pipe_;
std::string name_;
std::set<Stream *> streams_;
std::set<Stream *> activeStreams_;
private:
bool disconnected_;
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[] = {
"Available",
"Acquired",
@ -293,10 +305,31 @@ static const char *const camera_state_names[] = {
"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)
return true;
return 0;
ASSERT(static_cast<unsigned int>(low) < 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[high];
return false;
return -EACCES;
}
bool Camera::Private::stateIs(State state) const
void Camera::Private::disconnect()
{
if (state_ == state)
return true;
if (state_ == Private::CameraRunning)
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_]
<< " state trying operation requiring state "
<< camera_state_names[state];
return false;
void Camera::Private::setState(State state)
{
state_ = state;
}
/**
@ -468,8 +500,6 @@ Camera::Camera(PipelineHandler *pipe, const std::string &name,
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();
/*
* 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;
p_->disconnect();
disconnected.emit(this);
}
int Camera::exportFrameBuffers(Stream *stream,
std::vector<std::unique_ptr<FrameBuffer>> *buffers)
{
if (!p_->stateIs(Private::CameraConfigured))
return -EACCES;
int ret = p_->isAccessAllowed(Private::CameraConfigured);
if (ret < 0)
return ret;
if (streams().find(stream) == streams().end())
return -EINVAL;
@ -517,8 +540,9 @@ int Camera::exportFrameBuffers(Stream *stream,
int Camera::freeFrameBuffers(Stream *stream)
{
if (!p_->stateIs(Private::CameraConfigured))
return -EACCES;
int ret = p_->isAccessAllowed(Private::CameraConfigured, true);
if (ret < 0)
return ret;
p_->pipe_->freeFrameBuffers(this, stream);
@ -550,11 +574,9 @@ int Camera::freeFrameBuffers(Stream *stream)
*/
int Camera::acquire()
{
if (p_->disconnected_)
return -ENODEV;
if (!p_->stateIs(Private::CameraAvailable))
return -EBUSY;
int ret = p_->isAccessAllowed(Private::CameraAvailable);
if (ret < 0)
return ret == -EACCES ? -EBUSY : ret;
if (!p_->pipe_->lock()) {
LOG(Camera, Info)
@ -562,7 +584,7 @@ int Camera::acquire()
return -EBUSY;
}
p_->state_ = Private::CameraAcquired;
p_->setState(Private::CameraAcquired);
return 0;
}
@ -580,9 +602,10 @@ int Camera::acquire()
*/
int Camera::release()
{
if (!p_->stateBetween(Private::CameraAvailable,
Private::CameraConfigured))
return -EBUSY;
int ret = p_->isAccessAllowed(Private::CameraAvailable,
Private::CameraConfigured, true);
if (ret < 0)
return ret == -EACCES ? -EBUSY : ret;
if (allocator_) {
/*
@ -596,7 +619,7 @@ int Camera::release()
p_->pipe_->unlock();
p_->state_ = Private::CameraAvailable;
p_->setState(Private::CameraAvailable);
return 0;
}
@ -643,7 +666,12 @@ const std::set<Stream *> &Camera::streams() const
*/
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;
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 ret;
if (p_->disconnected_)
return -ENODEV;
if (!p_->stateBetween(Private::CameraAcquired,
Private::CameraConfigured))
return -EACCES;
int ret = p_->isAccessAllowed(Private::CameraAcquired,
Private::CameraConfigured);
if (ret < 0)
return ret;
if (allocator_ && allocator_->allocated()) {
LOG(Camera, Error)
@ -740,7 +764,7 @@ int Camera::configure(CameraConfiguration *config)
p_->activeStreams_.insert(stream);
}
p_->state_ = Private::CameraConfigured;
p_->setState(Private::CameraConfigured);
return 0;
}
@ -767,9 +791,9 @@ int Camera::configure(CameraConfiguration *config)
*/
Request *Camera::createRequest(uint64_t cookie)
{
if (p_->disconnected_ ||
!p_->stateBetween(Private::CameraConfigured,
Private::CameraRunning))
int ret = p_->isAccessAllowed(Private::CameraConfigured,
Private::CameraRunning);
if (ret < 0)
return nullptr;
return new Request(this, cookie);
@ -799,11 +823,9 @@ Request *Camera::createRequest(uint64_t cookie)
*/
int Camera::queueRequest(Request *request)
{
if (p_->disconnected_)
return -ENODEV;
if (!p_->stateIs(Private::CameraRunning))
return -EACCES;
int ret = p_->isAccessAllowed(Private::CameraRunning);
if (ret < 0)
return ret;
if (request->buffers().empty()) {
LOG(Camera, Error) << "Request contains no buffers";
@ -837,11 +859,9 @@ int Camera::queueRequest(Request *request)
*/
int Camera::start()
{
if (p_->disconnected_)
return -ENODEV;
if (!p_->stateIs(Private::CameraConfigured))
return -EACCES;
int ret = p_->isAccessAllowed(Private::CameraConfigured);
if (ret < 0)
return ret;
LOG(Camera, Debug) << "Starting capture";
@ -852,11 +872,11 @@ int Camera::start()
p_->pipe_->importFrameBuffers(this, stream);
}
int ret = p_->pipe_->start(this);
ret = p_->pipe_->start(this);
if (ret)
return ret;
p_->state_ = Private::CameraRunning;
p_->setState(Private::CameraRunning);
return 0;
}
@ -875,15 +895,13 @@ int Camera::start()
*/
int Camera::stop()
{
if (p_->disconnected_)
return -ENODEV;
if (!p_->stateIs(Private::CameraRunning))
return -EACCES;
int ret = p_->isAccessAllowed(Private::CameraRunning);
if (ret < 0)
return ret;
LOG(Camera, Debug) << "Stopping capture";
p_->state_ = Private::CameraConfigured;
p_->setState(Private::CameraConfigured);
p_->pipe_->stop(this);

View file

@ -314,7 +314,7 @@ const ControlInfoMap &PipelineHandler::controls(Camera *camera)
* exportFrameBuffers() and importFrameBuffers() for the streams contained in
* 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
* 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
* once per stream.
*
* The only intended callers are Camera::stop() and the FrameBufferAllocator
* helper.
* The only intended callers are Camera::stop() and Camera::freeFrameBuffers().
*/
/**