alexanderd5398
alexanderd5398

Reputation: 327

Unix Semaphore - unable to set initial value

I am trying to initiate a UNIX semaphore so that I can use it to control two processes.

I copied the sem_init function from this example. I removed the pshared parameter because it was not used in the function and corrected int * sem to int * semid assuming this was a mistake.

#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>

/* The semaphore key is an arbitrary long integer which serves as an
   external identifier by which the semaphore is known to any program
   that wishes to use it. */

using namespace std;

#define KEY (1492)

int sem_init(int* semid, unsigned int value) {
    /* get the semaphore */
    *semid = semget(KEY, 1, IPC_CREAT);
    if (*semid == -1) {
        printf("Unable to obtain semaphore.\n");
        return -1;
    } 

    int ret = semctl( *semid, 0, SETVAL, value);
    if (ret == -1) {
        printf("Unable to set semaphore value: %s\n", strerror(errno));
        return -1;
    }
    return ret;
}

int main(void) {
    int* semid = (int*) malloc(sizeof(int));
    sem_init(semid, 1);

    return 0;
}

The program prints Unable to set semaphore value: permission denied. I also copied the first main function from this example and it prints Cannot set semaphore value.

One thing I should mention is that there does seem to be processes running in the background from previous times that I have run the program, but it won't let me terminate them (it says operation not permitted), so maybe the semaphore is already initialized and it won't let me reinitialize it?

Also another thing. The first example passes IPC_CREAT | IPC_EXCL | 0666 to sem_get, but when I do this semget returns -1. It only works if just IPC_CREAT is passed.

If you could let me know what the 0666 does that would be great because none of the examples explain it.

Upvotes: 0

Views: 1080

Answers (2)

John Bollinger
John Bollinger

Reputation: 180201

The program prints Unable to set semaphore value: permission denied.

That would be because in the event that the semget() call you present in fact creates a new semaphore set, it creates it with no access permissions for anyone. You probably want something more like this:

*semid = semget(KEY, 1, IPC_CREAT | S_IRUSR | S_IWUSR);

That will assign mode 0600; add more permissions as needed. The S_ macros are documented with the open() function.

One thing I should mention is that there does seem to be processes running in the background from previous times that I have run the program, but it won't let me terminate them (it says operation not permitted), so maybe the semaphore is already initialized and it won't let me reinitialize it?

I don't see any reason why the particular program you presented would continue running in the background, but any semaphore set it creates has kernel persistence: it lives until explicitly removed, which will be past your particular program's termination. You should be able to use the ipcs command to get a list of current semaphores, and the ipcrm command to remove old ones. These may require root privilege.

The first example passes IPC_CREAT | IPC_EXCL | 0666 to sem_get, but when I do this semget returns -1. It only works if just IPC_CREAT is passed.

This is again the issue that your semaphore set outlives the program. When you specify IPC_EXCL, you are explicitly requesting that the call fail (returning -1) if a semaphore set with the specified key already exists, and therefore is not created fresh by the call. It should not be harmful to include the mode bits (the 0666) when omitting IPC_EXCL, but they have effect only when a new semaphore set is created. The S_IRUSR and S_IWUSR constants I referenced above represent two of the specific mode bits, and in general I recommend using the constants over encoding the mode numerically.

As an aside, note that the ftok() function is the conventional means to obtain a key value with which to identify a semaphore set.

Upvotes: 2

Andrew Henle
Andrew Henle

Reputation: 1

The problems with

*semid = semget(KEY, 1, IPC_CREAT | IPC_EXCL | 0666);

and

int ret = semctl( *semid, 0, SETVAL, value);

are almost certainly caused because the Sys V semaphore identified by *semid already exists with incorrect permissions, likely because an earlier creation left off the 0666 permissions. Since the semaphore id already exists, you can't attach to it with the IPC_EXCL flag set.

Assuming you're running on Linux, the ipcs -s command will show you the existing Sys V semaphores. You can then use the ipcrm command to remove the semaphore(s) with incorrect permissions and start over.

Upvotes: 2

Related Questions