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>
