|
|
| Next: anyone need games testers for linux? |
| Author |
Message |
user External

Since: Oct 28, 2004 Posts: 1
|
Posted: Thu Oct 28, 2004 9:25 am Post subject: semctl(semid, semop, GETPID, 0) bug ... need a workaround Archived from groups: linux>redhat>devel (more info?) |
|
|
The following code falls fowl of a linux kernel bug in ipc/sem.c
#include <sys/types.h>
#include <sys/sem.h>
#include <errno.h>
int main() {
int semid, res;
pid_t pid;
struct sembuf semops[2];
printf("parent: pid = %d\n", getpid());
/* create a semaphore set */
semid = semget(0xDEADBEEF, 1, IPC_CREAT|0666);
if (semid==-1) {
perror("parent: semget");
return 1;
}
printf("parent: semid = %d\n", semid);
/* raise the semaphore */
semops[0].sem_num = 0; /* Semaphore 0 */
semops[0].sem_op = 0; /* Test 0 */
semops[0].sem_flg = IPC_NOWAIT; /* dont wait */
semops[1].sem_num = 0;
semops[1].sem_op = 1; /* Increment */
semops[1].sem_flg = 0;
res = semop(semid, semops, 2);
if (res==-1) {
perror("parent: semop");
return 1;
}
printf("parent: got semaphore\n", semid);
/* Ok we have the semaphore... spawn a sub-process */
pid = fork();
if (pid == 0) {
printf("child: pid = %d\n", getpid());
/* get the semaphore set */
semid = semget(0xDEADBEEF, 1, IPC_CREAT|0666);
if (semid==-1) {
perror("child: semget");
return 1;
}
printf("child: semid = %d\n", semid);
/* raise the semaphore */
semops[0].sem_num = 0; /* Semaphore 0 */
semops[0].sem_op = 0; /* Test 0 */
semops[0].sem_flg = IPC_NOWAIT; /* dont wait */
semops[1].sem_num = 0;
semops[1].sem_op = 1; /* Increment */
semops[1].sem_flg = 0;
res = semop(semid, semops, 2);
if (res==-1 && errno==11) {
printf("child: resource locked\n");
/* Now, we should be able to query the semaphore and see */
/* who has it */
res = semctl(semid, 0, GETPID, 0);
if (res == -1) {
perror("child: semctl");
return 1;
}
printf("child: Pid %d last changed the semaphore\n", res);
/* all ok so far, however if we now try and obtain the lock */
/* again, we hit the bug... */
semops[0].sem_num = 0; /* Semaphore 0 */
semops[0].sem_op = 0; /* Test 0 */
semops[0].sem_flg = IPC_NOWAIT; /* dont wait */
semops[1].sem_num = 0;
semops[1].sem_op = 1; /* Increment */
semops[1].sem_flg = 0;
res = semop(semid, semops, 2);
if (res == -1 && errno==11) { /* We expect this */
printf("child: resource still locked\n");
res = semctl(semid, 0, GETPID, 0);
if (res == -1) {
perror("child: semctl");
return 1;
}
printf("child: ** THE BUG **\n");
printf("child: Pid %d last changed the semaphore\n", res);
printf("child: this should say\n");
printf("child: Pid %d last changed the semaphore\n",
getppid());
/* Give up */
return 0;
}
/* drop through to check result */
}
/* this should fail with errno 11 (which is ok) */
if (res==-1) {
perror("child: semop");
return 1;
}
printf ("child: got semaphore!! this should not have happened\n");
return 1;
}
sleep(2);
/* Release the semaphore */
res = semctl (semid, 0, SETVAL, 0);
if (res == -1) {
perror("parent: semctl SETVAL");
return 1;
}
res = semctl (semid, 0, IPC_RMID, 0);
if (res == -1) {
perror("parent: semctl IPC_RMID");
return 1;
}
return 0;
}
When run on kernels up to 2.4.20 (I have not been able to test later
kernels) the code produces the follwing output
parent: pid = 23783
parent: semid = 4358150
parent: got semaphore
child: pid = 23784
child: semid = 4358150
child: resource locked
child: Pid 23783 last changed the semaphore
child: resource still locked
child: ** THE BUG **
child: Pid 0 last changed the semaphore
child: this should say
child: Pid 23783 last changed the semaphore
The bug is that use of sem_op = 0, followed by sem_op = 1 (i.e. test 0
and increment) clobbers the PID of the last process to modify the
semaphore, but only on the 2nd attempt. The subsequent call to
semctl(GETPID) returns a PID of 0 which is incorrect.
I believe the fix is in kernel 2.4.22, but that is not currently an
option for me to go to that kernel. I need a workaround for this
problem that works on a 2.4.18 kernel.
Also, I need the workaround to work in a scenario where multiple
processes are testing the semaphore and one of them will initially
create the semaphore set, but it wont know for sure that it was the
process that created it. This is important, because I played with
using sem_op -1, trouble with that technique is something needs to
intialise the semaphore to 1 to begin with. But I can only safely do
this if I know it's not currently locked but as 0 means locked and when
the semaphore set is created it starts off as 0, I dont know if it's 0
becuase its locked or i just created it.
Is there any other form a suitably fast cross-process, mutex locking
that I could use?
I had thought about using flock() instead, but dont like the idea of
that. The lock file would have to be somewhere global, but somewhere
where it would not be deleted by accident or indeed on purpose), and it
needs to be pretty snappy (quick).
Ideally I would like a way to get semaphore's working. |
|
| Back to top |
|
 |
|
|
|
You can post new topics in this forum You can reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
| |
|
|