Logo Search packages:      
Sourcecode: batv-milter version File versions  Download package

sem.c

/*
 * Copyright (c) 2000-2001, 2005, 2008 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include <sm/gen.h>
SM_RCSID("@(#)$Id: sem.c,v 1.14 2008/05/30 16:26:38 ca Exp $")

#if SM_CONF_SEM
# include <stdlib.h>
# include <unistd.h>
# include <sm/string.h>
# include <sm/sem.h>
# include <sm/heap.h>
# include <errno.h>

/*
**  SM_SEM_START -- initialize semaphores
**
**    Parameters:
**          key -- key for semaphores.
**          nsem -- number of semaphores.
**          semflg -- flag for semget(), if 0, use a default.
**          owner -- create semaphores.
**
**    Returns:
**          id for semaphores.
**          < 0 on failure.
*/

int
sm_sem_start(key, nsem, semflg, owner)
      key_t key;
      int nsem;
      int semflg;
      bool owner;
{
      int semid, i, err;
      unsigned short *semvals;

      semvals = NULL;
      if (semflg == 0)
            semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3);
      if (owner)
            semflg |= IPC_CREAT|IPC_EXCL;
      semid = semget(key, nsem, semflg);
      if (semid < 0)
            goto error;

      if (owner)
      {
            union semun semarg;

            semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals);
            if (semvals == NULL)
                  goto error;
            semarg.array = semvals;

            /* initialize semaphore values to be available */
            for (i = 0; i < nsem; i++)
                  semvals[i] = 1;
            if (semctl(semid, 0, SETALL, semarg) < 0)
                  goto error;
      }
      return semid;

error:
      err = errno;
      if (semvals != NULL)
            sm_free(semvals);
      if (semid >= 0)
            sm_sem_stop(semid);
      return (err > 0) ? (0 - err) : -1;
}

/*
**  SM_SEM_STOP -- stop using semaphores.
**
**    Parameters:
**          semid -- id for semaphores.
**
**    Returns:
**          0 on success.
**          < 0 on failure.
*/

int
sm_sem_stop(semid)
      int semid;
{
      return semctl(semid, 0, IPC_RMID, NULL);
}

/*
**  SM_SEM_ACQ -- acquire semaphore.
**
**    Parameters:
**          semid -- id for semaphores.
**          semnum -- number of semaphore.
**          timeout -- how long to wait for operation to succeed.
**
**    Returns:
**          0 on success.
**          < 0 on failure.
*/

int
sm_sem_acq(semid, semnum, timeout)
      int semid;
      int semnum;
      int timeout;
{
      int r;
      struct sembuf semops[1];

      semops[0].sem_num = semnum;
      semops[0].sem_op = -1;
      semops[0].sem_flg = SEM_UNDO |
                      (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
      if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
            return semop(semid, semops, 1);
      do
      {
            r = semop(semid, semops, 1);
            if (r == 0)
                  return r;
            sleep(1);
            --timeout;
      } while (timeout > 0);
      return r;
}

/*
**  SM_SEM_REL -- release semaphore.
**
**    Parameters:
**          semid -- id for semaphores.
**          semnum -- number of semaphore.
**          timeout -- how long to wait for operation to succeed.
**
**    Returns:
**          0 on success.
**          < 0 on failure.
*/

int
sm_sem_rel(semid, semnum, timeout)
      int semid;
      int semnum;
      int timeout;
{
      int r;
      struct sembuf semops[1];

#if PARANOID
      /* XXX should we check whether the value is already 0 ? */
      SM_REQUIRE(sm_get_sem(semid, semnum) > 0);
#endif /* PARANOID */

      semops[0].sem_num = semnum;
      semops[0].sem_op = 1;
      semops[0].sem_flg = SEM_UNDO |
                      (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT);
      if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER)
            return semop(semid, semops, 1);
      do
      {
            r = semop(semid, semops, 1);
            if (r == 0)
                  return r;
            sleep(1);
            --timeout;
      } while (timeout > 0);
      return r;
}

/*
**  SM_SEM_GET -- get semaphore value.
**
**    Parameters:
**          semid -- id for semaphores.
**          semnum -- number of semaphore.
**
**    Returns:
**          value of semaphore on success.
**          < 0 on failure.
*/

int
sm_sem_get(semid, semnum)
      int semid;
      int semnum;
{
      int semval;

      if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0)
            return -1;
      return semval;
}

/*
**  SM_SEMSETOWNER -- set owner/group/mode of semaphores.
**
**    Parameters:
**          semid -- id for semaphores.
**          uid -- uid to use
**          gid -- gid to use
**          mode -- mode to use
**
**    Returns:
**          0 on success.
**          < 0 on failure.
*/

int
sm_semsetowner(semid, uid, gid, mode)
      int semid;
      uid_t uid;
      gid_t gid;
      mode_t mode;
{
# ifndef WIN32
      int r;
      struct semid_ds   semidds;
      union semun {
            int         val;
            struct semid_ds   *buf;
            ushort            *array;
      } arg;

      memset(&semidds, 0, sizeof(semidds));
      arg.buf = &semidds;
      if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0)
            return r;
      semidds.sem_perm.uid = uid;
      semidds.sem_perm.gid = gid;
      semidds.sem_perm.mode = mode;
      if ((r = semctl(semid, 1, IPC_SET, arg)) < 0)
            return r;
# endif /* WIN32 */
      return 0;
}
#endif /* SM_CONF_SEM */

Generated by  Doxygen 1.6.0   Back to index