There seems to be bug in $SUBJ. When I run attached program on recent
-CURRENT, it always (after several seconds) triggers the bug. I first
suspected a problem in the program's logic but on stable in runs just
fine.

Esentially I use piece of shm memory to pass some data between several
processes. I implemented simple locking functions with semaphores and
noticed it behaves strange on -CURRENT and ok on -STABLE.

CCing Alfred because he made some changes into the kernel part of $SUBJ. I
don't expect the bug is new though.

May I ask someone with older -CURRENT to try running the program for a
minute?

-- 
Michal Mertl
[EMAIL PROTECTED]


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define MY_SHM_MAGIC 0x56d9f13b

typedef struct {
        struct shmid_ds  shm_ds;
        struct semid_ds  sem_ds;
        pid_t            sem_owner;
        int              sem_id;
        int              shm_id;
        int              size;
} s_ipc_cfg;

s_ipc_cfg *ipc_cfg = NULL;

int
ipc_setup(int size)
{
        int skey;
        int ipc_tok;
        void *shm_addr;
        struct shmid_ds  shm_ds;
        union semun sem_arg;

        ipc_tok = IPC_PRIVATE;
        if ((skey = shmget(ipc_tok, size, SHM_R | SHM_W
                        | IPC_CREAT)) == -1) {
                fprintf(stderr, "shmget()\n");
                return (-1);
        }
        if ((shmctl(skey, IPC_STAT, &shm_ds)) == -1) {
                fprintf(stderr, "shmctl()\n");
                return (-1);
        }
        if ((shm_addr = shmat(skey, NULL, 0)) == (void *)-1) {
                fprintf(stderr, "shmat()\n");
                return (-1);
        }
        ipc_cfg = shm_addr;
        ipc_cfg->size = size - sizeof(s_ipc_cfg);
        memcpy(ipc_cfg, &shm_ds, sizeof(shm_ds));
        ipc_cfg->shm_id = skey;
        if (shmctl(ipc_cfg->shm_id, IPC_RMID, NULL) == -1) {
                fprintf(stderr, "shmctl() IPC_RMID\n");
                return (-1);
        }
        if ((skey = semget(ipc_tok, 1, SEM_R | SEM_A | IPC_CREAT)) == -1) {
                fprintf(stderr, "semget()\n");
                return (-1);
        }
        ipc_cfg->sem_id = skey;
        sem_arg.buf = (void *)&ipc_cfg->sem_ds;
        if (semctl(ipc_cfg->sem_id, 0, IPC_STAT, sem_arg) == -1) {
                fprintf(stderr, "semctl()\n");
                return (-1);
        }
        ipc_cfg->sem_owner = -1;
        sem_arg.val = 1;
        semctl(ipc_cfg->sem_id, 0, SETVAL, sem_arg);
        return (0);
}

void
ipc_shutdown(void)
{
        if (ipc_cfg)
                semctl(ipc_cfg->sem_id, 0, IPC_RMID);
}

int
ipc_lock(int wait, int undo)
{
        struct sembuf sem_buf;
        int              err;

        sem_buf.sem_num = 0;
        sem_buf.sem_op = -1;
        sem_buf.sem_flg =  wait ? 0 : IPC_NOWAIT;
        sem_buf.sem_flg |= undo ? SEM_UNDO : 0;
        err = semop(ipc_cfg->sem_id, &sem_buf, 1);
        if (err == -1) {
                if (wait && errno == EAGAIN)
                        return (-2);
                fprintf(stderr, "%d: semop()\n", getpid());
                return (-1);
        }
        printf("%d: ipc_lock()\n", getpid());
        ipc_cfg->sem_owner = getpid();
        return (0);
}

int
ipc_unlock(void)
{
        struct sembuf    sem_buf;
        int              err;

        if (ipc_cfg->sem_owner != getpid()) {
                fprintf(stderr, "%d: can't unlock (bug), owner: %d\n",
                        getpid(), ipc_cfg->sem_owner);
                return (-1);
        }
        if (semctl(ipc_cfg->sem_id, 0, GETVAL) != 0) {
                fprintf(stderr, "%d: can't unlock (bug), not locked\n",
                        getpid());
                return (-1);
        }
        printf("%d: ipc_unlock()\n", getpid());
        sem_buf.sem_num = 0;
        sem_buf.sem_op = 1;
        sem_buf.sem_flg = 0;
        err = semop(ipc_cfg->sem_id, &sem_buf, 1);
        if (err == -1) {
                fprintf(stderr, "%d: semop()\n", getpid());
                return (-1);
        }
        ipc_cfg->sem_owner = -1;
        return (0);
}

int
ipc_locked(void)
{
        return (semctl(ipc_cfg->sem_id, 0, GETVAL) ? 0 : 1);
}

int
ipc_owned(void)
{
        return (ipc_locked() &&
                ipc_cfg->sem_owner == getpid() ? 1 : 0);
}

int
ipc_useit(void)
{
        if (!ipc_owned()) {
                if (ipc_lock(1, 0) < 0) {
                        printf("%d: _ipc_getpart() can't lock\n",
                                        getpid());
                        return (-1);
                }
        }
        if (ipc_unlock() < 0) {
                fprintf(stderr, "%d: _ipc_getpart() can't unlock\n",
                                getpid());
                return (-1);
        }
        return (0);
}

int
be_child(void)
{
        for (;;) {
                usleep(10000 + random() % 5000);
                ipc_useit();
        }
        return (0);
}

int
main(int argc, char *argv[])
{
        srandomdev();
        if (ipc_setup(10000) < 0) {
                fprintf(stderr, "ipc_setup failed\n");
                return (EXIT_FAILURE);
        }
        switch (fork()) {
                case 0:
                        /* child */
                        be_child();
                        return (EXIT_SUCCESS);
                        break;
                case -1:
                        fprintf(stderr, "fork failed\n");
                        ipc_shutdown();
                        return (EXIT_FAILURE);
                default:
                        /* parent */
                        ;
        }
        if (atexit(ipc_shutdown) < 0) {
                fprintf(stderr, "atexit()\n");
                return (EXIT_FAILURE);
        }
        for (;;) {
                usleep(15000 + random() % 5000);
                ipc_useit();
        }
        return (EXIT_SUCCESS);
}

Reply via email to