v4l2: v4l2_camera_proxy: Serialize accesses to the proxy

Make the V4L2 compatibility layer thread-safe by serializing accesses to
the V4L2CameraProxy with a lock. Release the lock when blocking for
dqbuf.

Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
Paul Elder 2020-06-24 02:41:18 +09:00
parent 12fa2fe020
commit 0952f2014d
2 changed files with 21 additions and 5 deletions

View file

@ -45,6 +45,8 @@ int V4L2CameraProxy::open(V4L2CameraFile *file)
{
LOG(V4L2Compat, Debug) << "Servicing open fd = " << file->efd();
MutexLocker locker(proxyMutex_);
if (refcount_++) {
files_.insert(file);
return 0;
@ -79,6 +81,8 @@ void V4L2CameraProxy::close(V4L2CameraFile *file)
{
LOG(V4L2Compat, Debug) << "Servicing close fd = " << file->efd();
MutexLocker locker(proxyMutex_);
files_.erase(file);
release(file);
@ -94,6 +98,8 @@ void *V4L2CameraProxy::mmap(void *addr, size_t length, int prot, int flags,
{
LOG(V4L2Compat, Debug) << "Servicing mmap";
MutexLocker locker(proxyMutex_);
/* \todo Validate prot and flags properly. */
if (prot != (PROT_READ | PROT_WRITE)) {
errno = EINVAL;
@ -128,6 +134,8 @@ int V4L2CameraProxy::munmap(void *addr, size_t length)
{
LOG(V4L2Compat, Debug) << "Servicing munmap";
MutexLocker locker(proxyMutex_);
auto iter = mmaps_.find(addr);
if (iter == mmaps_.end() || length != sizeimage_) {
errno = EINVAL;
@ -587,7 +595,8 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)
return ret;
}
int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)
int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg,
MutexLocker *locker)
{
LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << file->efd();
@ -604,9 +613,11 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)
!validateMemoryType(arg->memory))
return -EINVAL;
if (!file->nonBlocking())
if (!file->nonBlocking()) {
locker->unlock();
vcam_->waitForBufferAvailable();
else if (!vcam_->isBufferAvailable())
locker->lock();
} else if (!vcam_->isBufferAvailable())
return -EAGAIN;
/*
@ -701,6 +712,8 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {
int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *arg)
{
MutexLocker locker(proxyMutex_);
if (!arg && (_IOC_DIR(request) & _IOC_WRITE)) {
errno = EFAULT;
return -1;
@ -761,7 +774,7 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *ar
ret = vidioc_qbuf(file, static_cast<struct v4l2_buffer *>(arg));
break;
case VIDIOC_DQBUF:
ret = vidioc_dqbuf(file, static_cast<struct v4l2_buffer *>(arg));
ret = vidioc_dqbuf(file, static_cast<struct v4l2_buffer *>(arg), &locker);
break;
case VIDIOC_STREAMON:
ret = vidioc_streamon(file, static_cast<int *>(arg));

View file

@ -61,7 +61,7 @@ private:
int vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg);
int vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg);
int vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg);
int vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg);
int vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg, MutexLocker *locker);
int vidioc_streamon(V4L2CameraFile *file, int *arg);
int vidioc_streamoff(V4L2CameraFile *file, int *arg);
@ -105,6 +105,9 @@ private:
* will return -EBUSY.
*/
V4L2CameraFile *owner_;
/* This mutex is to serialize access to the proxy. */
Mutex proxyMutex_;
};
#endif /* __V4L2_CAMERA_PROXY_H__ */