Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 6 Sep 2002 15:10:19 +0200 (CEST)
From:      Michal Mertl <mime@traveller.cz>
To:        current@freebsd.org
Cc:        alfred@freebsd.org
Subject:   bug in sysv semaphores on -CURRENT
Message-ID:  <Pine.BSF.4.41.0209061411380.77195-200000@prg.traveller.cz>

index | next in thread | raw e-mail

[-- Attachment #1 --]
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
mime@traveller.cz



[-- Attachment #2 --]
#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);
}

home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.41.0209061411380.77195-200000>