Pls sanity check my semtimedop(2) implementation

Michael B Allen ioplex at gmail.com
Sun Jul 13 15:13:16 UTC 2008


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.

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