I am working on a school assignment using semaphores, every time I restart my mechine everything works as expected but after running my code, the second try gives undefined results. I've come to a conclusion that my machine don't give me permission to unlink any created semaphores, and checking the errno showed that my conclusion was correct. It gives errno EACCES, how can I fix this problem? I am working on the last visions of Xcode (12.2).
The code I am running:
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h> /* For O_* constants */
#include <errno.h>
const char *semName1 = "my_sema1";
const char *semName2 = "my_sema2";
int main(int argc, char **argv)
{
pid_t pid;
sem_t *sem_id1 = sem_open(semName1, O_CREAT, O_RDWR, 1);
sem_t *sem_id2 = sem_open(semName2, O_CREAT, O_RDWR, 0);
int i, status;
pid = fork();
if (pid) {
for (i = 0; i < 100; i++) {
sem_wait(sem_id1);
putchar('A'); fflush(stdout);
sem_post(sem_id2);
}
sem_close(sem_id1);
sem_close(sem_id2);
wait(&status);
int error = sem_unlink(semName1);
int hej2 = sem_unlink(semName2);
printf("%d \n",error);
if (errno == EACCES){
printf("%d \n",error);
}
} else {
for (i = 0; i < 100; i++) {
sem_wait(sem_id2);
putchar('B'); fflush(stdout);
sem_post(sem_id1);
}
sem_close(sem_id1);
sem_close(sem_id2);
}
}
Appreciate your help
Quick Answer: Run the program as root
Long Answer:
Given this code snippet:
#include <errno.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
sem_t *sem_id1 = sem_open("sem_id1", O_CREAT, O_RDWR, 0);
if (sem_id1 == SEM_FAILED)
{
perror("sem_open");
exit(1);
}
printf("sem_open: Successful\n");
int rc = sem_unlink("sem_id1");
if (rc != 0)
{
perror("sem_unlink");
exit(1);
}
printf("sem_unlink: Successful\n");
return 0;
}
The first time it's run, it will let you create the semaphore, but fail to unlink it:
./main
sem_open: Successful
sem_unlink: Permission denied
The second time it will fail even to create the semaphore:
./main
sem_open: Permission denied
The issue is clearly with permissions, and running the program as root fixes it:
sudo ./main
sem_open: Successful
sem_unlink: Successful
Why does it need root privileges?
Quoting from the man page:
POSIX semaphores come in two forms: named semaphores and unnamed semaphores.
...
Persistence
POSIX named semaphores have kernel persistence: if not removed by sem_unlink(3), a semaphore will exist until the system is shut down.
These are named semaphores.
The fn sem_open and sem_unlink are possibly affecting processes that don't belong to you: imagine if you could run a program that overwrites or removes another process' semaphore without root permissions!
Related
I'm trying to migrate a multiprocess application to Docker. Different processes will be placed in different Docker container.
The application uses shared memory to exchange data and semaphores to synchronize. I already recompiled Docker in order to do not use the IPC namespace and I effectively checked with sudo ipcs -m that the shared memory buffers are accessible from the different containers.
The problem is that semaphores are not working. I wrote these simple programs to check the behavior of POSIX semaphores in Docker:
/* To be compiled with -lpthread */
#include <stdio.h>
#include <fcntl.h>
#include <semaphore.h>
int main(void) {
int ret, val;
sem_t * mySem;
printf("[ONE] Opening the semaphore...\n");
mySem = sem_open("sem1", O_CREAT, 0777, 0);
if (mySem == SEM_FAILED) {
printf("[ONE] Error on sem_open()\n");
return -1;
}
ret = sem_post(mySem);
getchar(); // Awful way to block execution of [ONE] for a while...
printf("[ONE] Waiting for [TWO]...\n");
ret = sem_wait(mySem);
printf("[ONE] Wait ended\n");
ret = sem_unlink("sem1");
printf("[ONE] Semaphore destroyed\n");
return 0;
}
The second program is:
/* To be compiled with -lpthread */
#include <stdio.h>
#include <fcntl.h>
#include <semaphore.h>
int main(void) {
int ret;
int val;
sem_t * mySem;
printf("[TWO] Opening the semaphore...\n");
mySem = sem_open("sem1", O_CREAT, 0777, 0);
if (mySem == SEM_FAILED) {
printf("[TWO] Error on sem_open()\n");
return -1;
}
ret = sem_getvalue(mySem, &val);
printf("[TWO] Semaphore's value is %d\n", val);
printf("[TWO] Waiting for [ONE]...\n");
ret = sem_wait(mySem);
printf("[TWO] Wait ended\n");
printf("[ONE] Doing sem_post() on semaphore...\n");
ret = sem_post(mySem);
ret = sem_close(mySem);
printf("[TWO] Semaphore closed\n");
return 0;
}
In both I omitted lots of controls like if (ret != 0) {...} in order to maintain readability of the question.
I run the first program on the host machine, the second one in a Docker container. The result is that the second program waits forever...
The question is: is it possible in some way to use POSIX semaphores between Docker containers or between a container and the host?
I solved the problem using shared memory between Docker containers as explained in this question.
The following code is a modified version of this tutorial.
File server.c
/* To be compiled with -lpthread */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <semaphore.h>
#define SHM_SIZE 1000
int main(void) {
int shmid;
key_t key;
char *shm;
sem_t * mySem;
/* We'll name our shared memory segment "5678" */
key = 5678;
/* Create the segment.*/
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666)) < 0) {
perror("shmget");
exit(1);
}
/* Now we attach the segment to our data space */
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
/* Create a new semaphore */
mySem = sem_open("sem1", O_CREAT, 0777, 0);
/* Copy the semaphore on the shared memory segment */
memcpy(shm, mySem, sizeof(*mySem));
/* Do stuff ... */
/* REMEMBER TO USE THE SHARED MEMORY SEGMENT */
/* AND NOT THE LOCAL mySem, USE (sem_t*)shm INSTEAD! */
/* Finally, we wait until the other process
* changes the first character of our memory
* to '*', indicating that it has read what
* we put there.
*/
while (*shm != '*')
sleep(1);
/* Mark the memory segment to be destroyed */
shmctl(shmid, IPC_RMID, NULL);
/* Detach of the memory segment */
shmdt(&shm);
sem_unlink("sem1");
return 0;
}
File client.c
/* To be compiled with -lpthread */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <semaphore.h>
#define SHM_SIZE 1000
int main(void) {
int shmid;
key_t key;
char *shm;
int ret, val;
key = 5678;
if ((shmid = shmget(key, SHM_SIZE, 0666)) < 0) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
/* SEMAPHORE IS IN THE SHARED MEMORY SEGMENT */
/* USE (sem_t*)shm TO ACCESS IT */
*shm = '*';
shmdt(&shm);
sem_close("sem1");
return 0;
}
The code examples miss lots of controls due to readability purposes.
I run the server on the host machine, the client inside a Docker container and checked that the semaphore was accessible from both processes.
I am relatively new to programming, especially in the C Language.
I got an assignment to write a simple program in C and executing it in Linux.
I've written the code already as below:
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#define BUFSZ 4096
int shmid;
int shmkey = 12222;
int main()
{
/* ----- Creating Shared memory ----- */
shmid=shmget(IPC_PRIVATE,BUFSZ,0666);
if(shmid<0)
{
perror("shmget");
exit(EXIT_FAILURE);
}
printf(" Segment Created: %d \n", shmid);
/* ----- Attaching Memory to Shared memory ----- */
char *shmbuf;
if((shmbuf=shmat(shmid,0,0))<0)
{
perror("shmat");
exit(EXIT_FAILURE);
}
printf("Segmet Attached at %p \n", shmbuf);
//system("ipcs -m");
/* ----- Creating Process Using Fork ----- */
int p,i; //i is counter
for (i=1; i<=20; i++) //loop for counter
{
p=fork(); //defining fork
if (p<0)
{
printf("Fork Failed"); //Fork Fails if P<0
exit(-1);
}
else if (p==0) //Child Process
{
printf("Counter: %d\t Process ID: %d\n" ,i,getpid());
//Prints Counter Value and Process ID.
}
else //Parent Process
{
wait(NULL); //Waits Child Process to Complete
exit(0);
}
}
/* ----- Deattaching Memory -----*/
if((shmdt(shmbuf))<0)
{
perror("shmat");
exit(EXIT_FAILURE);
}
printf("Segmet Deattached at %p \n", shmbuf);
//system("ipcs -m");
/* ----- Exiting Program ----- */
exit(0);
puts("\n End\n");
}
I now have to apply the concept of semaphore to this program, using semget(), semop(), and semctl(). Can I please get help on how to use the three functions in my program?
The advantage of semaphores over other synchronization mechanisms is that they can be used to synchronize two related or unrelated processes trying to access the same resource.
Related Process
The processes are said to be related if the new process is created from within an existing process, which ends up in duplicating the resources of the creating process. Such processes are called related processes. The following example shows how the related processes are synchronized.
file prog.c
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char **argv) { int fd, i,count=0,nloop=10,zero=0,*ptr; sem_t mutex;
//open a file and map it into memory
fd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU); write(fd,&zero,sizeof(int)); ptr = mmap(NULL,sizeof(int),PROT_READ |PROT_WRITE,MAP_SHARED,fd,0); close(fd);
/* create, initialize semaphore */ if( sem_init(&mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
} if (fork() == 0) { /* child process*/
for (i = 0; i < nloop; i++) {
sem_wait(&mutex);
printf("child: %d\n", (*ptr)++);
sem_post(&mutex);
}
exit(0); } /* back to parent process */ for (i = 0; i < nloop; i++) {
sem_wait(&mutex);
printf("parent: %d\n", (*ptr)++);
sem_post(&mutex); } exit(0); }
gcc prog.c -lpthread
In this example, the related process access a common piece of memory, which is synchronized.
Unrelated Process
Processes are said to be unrelated if the two processes are unknown to each other and no relationship exists between them. For example, instances of two different programs are unrelated process. If such programs try to access a shared resource, a semaphore could be used to synchronize their access. The following source code demonstrates this:
file 1: server.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SHMSZ 27
char SEM_NAME[]= "vik";
int main()
{
char ch;
int shmid;
key_t key;
char *shm,*s;
sem_t *mutex;
//name the shared memory segment
key = 1000;
//create & initialize semaphore
mutex = sem_open(SEM_NAME,O_CREAT,0644,1);
if(mutex == SEM_FAILED)
{
perror("unable to create semaphore");
sem_unlink(SEM_NAME);
exit(-1);
}
//create the shared memory segment with this key
shmid = shmget(key,SHMSZ,IPC_CREAT|0666);
if(shmid<0)
{
perror("failure in shmget");
exit(-1);
}
//attach this segment to virtual memory
shm = shmat(shmid,NULL,0);
//start writing into memory
s = shm;
for(ch='A';ch<='Z';ch++)
{
sem_wait(mutex);
*s++ = ch;
sem_post(mutex);
}
//the below loop could be replaced by binary semaphore
while(*shm != '*')
{
sleep(1);
}
sem_close(mutex);
sem_unlink(SEM_NAME);
shmctl(shmid, IPC_RMID, 0);
_exit(0);
}
gcc server.c -lpthread -o server
File 2: client.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SHMSZ 27
char SEM_NAME[]= "vik";
int main()
{
char ch;
int shmid;
key_t key;
char *shm,*s;
sem_t *mutex;
//name the shared memory segment
key = 1000;
//create & initialize existing semaphore
mutex = sem_open(SEM_NAME,0,0644,0);
if(mutex == SEM_FAILED)
{
perror("reader:unable to execute semaphore");
sem_close(mutex);
exit(-1);
}
//create the shared memory segment with this key
shmid = shmget(key,SHMSZ,0666);
if(shmid<0)
{
perror("reader:failure in shmget");
exit(-1);
}
//attach this segment to virtual memory
shm = shmat(shmid,NULL,0);
//start reading
s = shm;
for(s=shm;*s!=NULL;s++)
{
sem_wait(mutex);
putchar(*s);
sem_post(mutex);
}
//once done signal exiting of reader:This can be replaced by another semaphore
*shm = '*';
sem_close(mutex);
shmctl(shmid, IPC_RMID, 0);
exit(0);
}
gcc client.c -lpthread -o client
The above executables (client and server) demonstrate how semaphore could be used between completely different processes.
In addition to the applications shown above, semaphores can be used cooperatively to access a resource. Please note that a semaphore is not a Mutex. A Mutex allows serial access to a resource, whereas semaphores, in addition to allowing serial access, could also be used to access resources in parallel. For example, consider resource R being accessed by n number of users. When using a Mutex, we would need a Mutex "m" to lock and unlock the resource, thus allowing only one user at a time to use the resource R. In contrast, semaphores can allow n number of users to synchronously access the resource R.
In the following code, wouldn't a mutex be created, in the child, as a copy of its parent's? Hence there're two copies of mutexs now -- one in child, and one in parent. How can it be synchronized? As far as I can remember, you need one copy that are shared by multiple processes in order to make it synchronize.
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char **argv)
{
int fd, i,count=0,nloop=10,zero=0,*ptr;
sem_t mutex;
//open a file and map it into memory
fd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU);
write(fd,&zero,sizeof(int));
ptr = mmap(NULL,sizeof(int), PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
close(fd);
/* create, initialize semaphore */
if( sem_init(&mutex,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
if (fork() == 0) { /* child process*/
for (i = 0; i < nloop; i++) {
sem_wait(&mutex);
printf("child: %d\n", (*ptr)++);
sem_post(&mutex);
}
exit(0);
}
/* back to parent process */
for (i = 0; i < nloop; i++) {
sem_wait(&mutex);
printf("parent: %d\n", (*ptr)++);
sem_post(&mutex);
}
exit(0);
}
You must not confuse a mutex with a semaphore. A semaphore might allow several threads/processes to access a resource, a mutex allows only ONE concurrent access to a resource.
As stated here you would need to create a named semaphore to make cross-process-synchronisation possible.
You must create a semaphore in your parent process and access is using sem_open in the child process to achieve synchronisation.
This is the producer.
// speak.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define FIFO_NAME "american_maid"
int main(void)
{
char s[300];
int num, fd;
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
printf("waiting for readers...\n");
fd = open(FIFO_NAME, O_WRONLY);
printf("got a reader--type some stuff\n");
while (gets(s), !feof(stdin)) {
if ((num = write(fd, s, strlen(s))) == -1)
perror("write");
else
printf("speak: wrote %d bytes\n", num);
}
return 0;
}
And this is the consumer.
//tick.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define FIFO_NAME "american_maid"
int main(void)
{
char s[300];
int num, fd;
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
printf("waiting for writers...\n");
fd = open(FIFO_NAME, O_RDONLY);
printf("got a writer\n");
do {
if ((num = read(fd, s, 300)) == -1)
perror("read");
else {
s[num] = '\0';
printf("tick: read %d bytes: \"%s\"\n", num, s);
}
} while (num > 0);
return 0;
}
When I run them, Producer outputs,
waiting for readers...
And consumer outputs,
waiting for writers...
speak doesn't find the reader, tick. As from the theory here I got that, open() (speak.c) will be keep blocked until open() (tick.c) is opened. And the vice versa. So I guess there a deadlock or something happening. I need a solution of this.
It looks like you have a race condition between the reader and the writer.
To fix this, you need a method of not launching the reader until the writer is "active". For this, I'd suggest making a pipe and writing to it when the writer is ready. Then, when reading from the read end of the fork succeeds, the fifo is prepared and the reader should work.
You need to use forks here because coordinating mutexes between a parent and a child process is non-trivial and properly done pipes is easier.
Also, you called mknod() twice. Granted, it'll return -1 with errno == EEXIST, but be more careful. To avoid this, make the reader and writer a function that takes a path as an argument.
Rewrite your writer as int speak(const char *fifo, int pipefd) and your reader as int tick(const char *fifo).
Then make a wrapper like this:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
const char fifo_name[] /* = ... */;
int speak(const char *fifo, int pipefd);
int tick(const char *fifo);
int main() {
int pipefd[2];
pipe(pipefd);
mknod(fifo_name, S_IFIFO | 0666, 0);
if (fork() == 0) {
close(pipefd[0]);
return speak(fifo_name, pipefd[1]);
} else {
close(pipefd[1]);
char foo;
read(pipefd[0], &foo, 1);
return tick(fifo_name);
}
}
Modify your writer to print a byte (of anything) to the passed fd after the fifo is created (i.e. right after the call to open(..., O_WRONLY)).
Don't use my code verbatim, as I've omitted error checking for the sake of brevity.
it runs ok in my env. and if reader and writer is ready, open will return. because open is blocked, so in my opinion, mknod function is success. May be you excute these two process at different path.
I'm experiencing a lot of difficulty getting Semaphores to work on a Linux based system in C.
The process of my application is such:
Application starts
Application forks into child/parent
Each process uses sem_open with a common name to open the semaphore.
If I create the semaphore before forking, it works fine. However, requirements prevent me from doing so. When I try to call sem_open for the second time, I get a "Permission Denied" error (via errno).
Is it possible to do this in any way? Or is there any way to open the semaphore in one process and used a shared memory mechanism to share it with the child process?
Don't forget to specify the mode and value parameter when using O_CREAT in the flags.
Here is a working example :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
static void parent(void)
{
sem_t * sem_id;
sem_id=sem_open("mysem", O_CREAT, 0600, 0);
if(sem_id == SEM_FAILED) {
perror("parent sem_open");
return;
}
printf("waiting for child\n");
if(sem_wait(sem_id) < 0) {
perror("sem_wait");
}
}
static void child(void)
{
sem_t * sem_id;
sem_id=sem_open("mysem", O_CREAT, 0600, 0);
if(sem_id == SEM_FAILED) {
perror("child sem_open");
return;
}
printf("Posting for parent\n");
if(sem_post(sem_id) < 0) {
perror("sem_post");
}
}
int main(int argc, char *argv[])
{
pid_t pid;
pid=fork();
if(pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if(!pid) {
child();
} else {
int status;
parent();
wait(&status);
}
return 0;
}
Are you using the 4 parameter or 2 parameter version of sem_open?
Make sure to use the 4 parameter version and use a mode that will allow other processes to open the semaphore. Assuming all the processes are owned by the same user, a mode of 0600 (S_IRUSR | S_IWUSR) will be sufficient.
You may also want to verify that you umask is not masking out any of the necessary permissions.