uvc open/close race (Was Re: v4l1 compat wrapper version 0.3)

Hans de Goede <[email protected]> Fri, 06 Jun 2008 16:19:28 +0200
Newsgroups gmane.comp.video.video4linux,gmane.linux.drivers.spca50x.devel
Message-ID <[email protected]>
Laurent Pinchart wrote:
> Hi Hans,
> 
> On Friday 06 June 2008 15:00, Hans de Goede wrote:
>> Hi All,
>>
>> Ok, this one _really_ works with ekiga (and still works fine with spcaview)
>> and also works with camorama with selected cams (not working on some cams
>> due to a camorama bug).
>>
>> Changes:
>> * Don't allow multiple opens, in theory our code can handle it, but not all
>>    v4l2 devices like it (ekiga does it and uvc doesn't like it).
> 
> Could you please elaborate ? Have you noticed a bug in the UVC driver ? It 
> should support multiple opens.

A good question, which I kinda knew I had coming. So now it has been asked I've 
spend some time tracking this down. There seems to be an open/close race 
somewhere in the UVC driver, ekiga does many open/close cycles in quick 
succession during probing.

It seems my no multiple opens code slows it down just enough to stop the race, 
but indeed multiple opens does not seem to be the real problem.

I've attached a program which reproduces it. I've commented out the fork as 
that does not seem necessary to reproduce this, just very quickly doing
open/some-io/close, open/some-io/close seems to be enough to trigger this, here 
is the output on my machine:

[hans@localhost v4l1-compat-0.4]$ ./test
[hans@localhost v4l1-compat-0.4]$ ./test
[hans@localhost v4l1-compat-0.4]$ ./test
[hans@localhost v4l1-compat-0.4]$ ./test
TRY_FMT 2: Input/output error
[hans@localhost v4l1-compat-0.4]$ ./test
TRY_FMT 1: Input/output error
[hans@localhost v4l1-compat-0.4]$ ./test
TRY_FMT 1: Input/output error
[hans@localhost v4l1-compat-0.4]$ ./test
TRY_FMT 1: Input/output error
[hans@localhost v4l1-compat-0.4]$

Notice how after the first time it gets the I/O error, it never recovers and 
from now on every first TRY_FMT fails.

Some notes:
1) TRY_FMT should really never do I/O (but then I guess the
    problem would still persists with S_FMT)
2) I've also seen it fail at TRY_FMT 1 without first failing
    a TRY_FMT 2, I guess that was just me doing arrow-up -> enter to quickly :)

Regards,

Hans

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
test.c (text/plain, 1.2 KB)
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <syscall.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>

int main(void)
{
  int fd;
  pid_t pid;
  struct v4l2_format fmt2 = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
  
  fd = open("/dev/video0", O_RDONLY);
  if (fd == -1) {
    perror("open 1");
    return 1;
  }

  if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt2)) {
    perror("G_FMT 1");
    return 1;
  }
      
  if (syscall(SYS_ioctl, fd, VIDIOC_TRY_FMT, &fmt2)) {
    perror("TRY_FMT 1");
    return 1;
  }

  if (syscall(SYS_ioctl, fd, VIDIOC_S_FMT, &fmt2)) {
    perror("S_FMT 1");
    return 1;
  }

/*  pid = fork();
  if (pid == -1) {
    perror("fork");
    return 1;
  }
  
  if (!pid) {
    close(fd);
  } else */ {
    close(fd);
    fd = open("/dev/video0", O_RDONLY);
    if (fd == -1) {
      perror("open 2");
      return 1;
    }

    if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt2)) {
      perror("G_FMT 2");
      return 1;
    }
        
    if (syscall(SYS_ioctl, fd, VIDIOC_TRY_FMT, &fmt2)) {
      perror("TRY_FMT 2");
      return 1;
    }

    if (syscall(SYS_ioctl, fd, VIDIOC_S_FMT, &fmt2)) {
      perror("S_FMT 2");
      return 1;
    }
  }
  return 0;
}