Pls sanity check my semtimedop(2) implementation

Michael B Allen ioplex at gmail.com
Sun Jul 13 21:09:24 UTC 2008


On 7/13/08, Mikko Työläjärvi <mbsd at pacbell.net> wrote:
> On Sun, 13 Jul 2008, Michael B Allen wrote:
>
>
> > Hi,
> >
> > Below is a semtimedop(2) implementation that I'm using for FreeBSD. I
> > was hoping someone could look it over and tell me if they think the
> > implementation is sound.
> >
> > The code seems to work ok but when stressing the FreeBSD build of my app
> > I have managed to provoke errors related to concurrency (usually when a
> > SIGALRM goes off). The Linux build works flawlessesly so I'm wondering
> > about this one critical function that is different.
> >
>
>  At the very least you need to check errno when semop() returns -1.
>  Unless it is EINTR, you have other problems.
>
>  Also, if there is any other code using the timer across this function
>  call, you have race conditions between changing the signal handler and
>  setting the timer.  Even if there is no other use of the timer across
>  this function, resetting the signal handler before disarming the timer
>  leaves you open to the signal being handled by the default handler
>  which will make the process exit.

Hi Mikko,

So if some other code uses setitimer(2) for whatever reason, then I
have the potential for a race. I'm not aware of any other such
instances of setitimer but my app is actually a plugin for a larger
application so I can't entirely rule out the possibility.

Is there any facility for creating a stateful timer so that I don't
run into this problem?

Can anyone provide the basis for an alternative implementation?

Should I use select(2) instead?

Mike

> > Is there any reason why I would want to use ITIMER_VIRTUAL /
> > SIGVTALRM instead of ITIMER_REAL / SIGALRM?
> >
> > Or perhaps I should be using a different implementation entirely?
> >
> > Mike
> >
> > int
> > _semtimedop(int semid,
> >      struct sembuf *array,
> >      size_t nops,
> >      struct timespec *_timeout)
> > {
> >  struct timeval timeout, before, after;
> >  struct itimerval value, ovalue;
> >  struct sigaction sa, osa;
> >  int ret;
> >
> >  if (_timeout) {
> >      timeout.tv_sec = _timeout->tv_sec;
> >      timeout.tv_usec = _timeout->tv_nsec / 1000;
> >
> >      if (gettimeofday(&before, NULL) == -1) {
> >          return -1;
> >      }
> >
> >      memset(&value, 0, sizeof value);
> >      value.it_value = timeout;
> >
> >      memset(&sa, 0, sizeof sa);
> >      /* signal_print writes the signal info to a log file
> >       */
> >      sa.sa_sigaction = signal_print;
> >      sa.sa_flags = SA_SIGINFO;
> >      sigemptyset(&sa.sa_mask);
> >      sigaction(SIGALRM, &sa, &osa);
> >
> >      if (setitimer(ITIMER_REAL, &value, &ovalue) == -1) {
> >          sigaction(SIGALRM, &osa, NULL);
> >          return -1;
> >      }
> >  }
> >
> >  ret = semop(semid, array, nops);
> >
> >  if (_timeout) {
> >      sigaction(SIGALRM, &osa, NULL);
> >
> >      if (setitimer(ITIMER_REAL, &ovalue, NULL) == -1) {
> >          return -1;
> >      }
> >  }
> >
> >  if (ret == -1) {
> >      if (_timeout) {
> >          struct timeval elapsed;
> >
> >          if (gettimeofday(&after, NULL) == -1) {
> >              return -1;
> >          }
> >
> >          _timeval_diff(&after, &before, &elapsed);
> >
> >          if (timercmp(&elapsed, &timeout, >=))
> >              errno = EAGAIN;
> >      }
> >
> >      return -1;
> >  }
> >
> >  return 0;
> > }


More information about the freebsd-hackers mailing list