root/usr/src/cmd/sendmail/libsm/t-shm.c
/*
 * Copyright (c) 2000-2002, 2004, 2005 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: t-shm.c,v 1.22 2005/01/14 02:14:10 ca Exp $")

#include <stdio.h>

#if SM_CONF_SHM
# include <stdlib.h>
# include <unistd.h>
# include <sys/wait.h>

# include <sm/heap.h>
# include <sm/string.h>
# include <sm/test.h>
# include <sm/shm.h>

# define SHMSIZE        1024
# define SHM_MAX        6400000
# define T_SHMKEY       21


/*
**  SHMINTER -- interactive testing of shared memory
**
**      Parameters:
**              owner -- create segment.
**
**      Returns:
**              0 on success
**              < 0 on failure.
*/

int shminter __P((bool));

int
shminter(owner)
        bool owner;
{
        int *shm, shmid;
        int i, t;

        shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
        if (shm == (int *) 0)
        {
                perror("shminit failed");
                return -1;
        }

        while ((t = getchar()) != EOF)
        {
                switch (t)
                {
                  case 'c':
                        *shm = 0;
                        break;
                  case 'i':
                        ++*shm;
                        break;
                  case 'd':
                        --*shm;
                        break;
                  case 's':
                        sleep(1);
                        break;
                  case 'l':
                        t = *shm;
                        for (i = 0; i < SHM_MAX; i++)
                        {
                                ++*shm;
                        }
                        if (*shm != SHM_MAX + t)
                                fprintf(stderr, "error: %d != %d\n",
                                        *shm, SHM_MAX + t);
                        break;
                  case 'v':
                        printf("shmval: %d\n", *shm);
                        break;
                  case 'S':
                        i = sm_shmsetowner(shmid, getuid(), getgid(), 0644);
                        printf("sm_shmsetowner=%d\n", i);
                        break;
                }
        }
        return sm_shmstop((void *) shm, shmid, owner);
}


/*
**  SHMBIG -- testing of shared memory
**
**      Parameters:
**              owner -- create segment.
**              size -- size of segment.
**
**      Returns:
**              0 on success
**              < 0 on failure.
*/

int shmbig __P((bool, int));

int
shmbig(owner, size)
        bool owner;
        int size;
{
        int *shm, shmid;
        int i;

        shm = (int *) sm_shmstart(T_SHMKEY, size, 0, &shmid, owner);
        if (shm == (int *) 0)
        {
                perror("shminit failed");
                return -1;
        }

        for (i = 0; i < size / sizeof(int); i++)
                shm[i] = i;
        for (i = 0; i < size / sizeof(int); i++)
        {
                if (shm[i] != i)
                {
                        fprintf(stderr, "failed at %d: %d", i, shm[i]);
                }
        }

        return sm_shmstop((void *) shm, shmid, owner);
}


/*
**  SHMTEST -- test of shared memory
**
**      Parameters:
**              owner -- create segment.
**
**      Returns:
**              0 on success
**              < 0 on failure.
*/

# define MAX_CNT        10

int shmtest __P((int));

int
shmtest(owner)
        int owner;
{
        int *shm, shmid;
        int cnt = 0;

        shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
        if (shm == (int *) 0)
        {
                perror("shminit failed");
                return -1;
        }

        if (owner)
        {
                int r;

                r = sm_shmsetowner(shmid, getuid(), getgid(), 0660);
                SM_TEST(r == 0);
                *shm = 1;
                while (*shm == 1 && cnt++ < MAX_CNT)
                        sleep(1);
                SM_TEST(cnt <= MAX_CNT);

                /* release and re-acquire the segment */
                r = sm_shmstop((void *) shm, shmid, owner);
                SM_TEST(r == 0);
                shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
                SM_TEST(shm != (int *) 0);
        }
        else
        {
                while (*shm != 1 && cnt++ < MAX_CNT)
                        sleep(1);
                SM_TEST(cnt <= MAX_CNT);
                *shm = 2;

                /* wait a momemt so the segment is still in use */
                sleep(2);
        }
        return sm_shmstop((void *) shm, shmid, owner);
}

int
main(argc, argv)
        int argc;
        char *argv[];
{
        bool interactive = false;
        bool owner = false;
        int big = -1;
        int ch;
        int r = 0;
        int status;
        extern char *optarg;

# define OPTIONS        "b:io"
        while ((ch = getopt(argc, argv, OPTIONS)) != -1)
        {
                switch ((char) ch)
                {
                  case 'b':
                        big = atoi(optarg);
                        break;

                  case 'i':
                        interactive = true;
                        break;

                  case 'o':
                        owner = true;
                        break;

                  default:
                        break;
                }
        }

        if (interactive)
                r = shminter(owner);
        else if (big > 0)
                r = shmbig(true, big);
        else
        {
                pid_t pid;
                extern int SmTestNumErrors;

                if ((pid = fork()) < 0)
                {
                        perror("fork failed\n");
                        return -1;
                }

                sm_test_begin(argc, argv, "test shared memory");
                if (pid == 0)
                {
                        /* give the parent the chance to setup data */
                        sleep(1);
                        r = shmtest(false);
                }
                else
                {
                        r = shmtest(true);
                        (void) wait(&status);
                }
                SM_TEST(r == 0);
                if (SmTestNumErrors > 0)
                        printf("add -DSM_CONF_SHM=0 to confENVDEF in devtools/Site/site.config.m4\nand start over.\n");
                return sm_test_end();
        }
        return r;
}
#else /* SM_CONF_SHM */
int
main(argc, argv)
        int argc;
        char *argv[];
{
        printf("No support for shared memory configured on this machine\n");
        return 0;
}
#endif /* SM_CONF_SHM */