Processes and semaphores - c

So i was experimenting on how to use fork and semaphores for a homework and it seems everytime i run the program fork always returns a number >0, while what i wanted was to first have several processes be made then be stopped using semaphores and then have some of them restart again.
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
int main(int argc,char *argv[])
{
int i,count;
count = 0;
pid_t *Pc;
Pc=(pid_t *) malloc((argc-2)*sizeof(pid_t));
sem_t *sem;
sem = (sem_t *) malloc((argc-2)*sizeof(sem_t));
for (i = 0; i <= argc-2; i++){
sem_init(&sem[i], 0, 0);
}
for (i =0; i<=argc-2; i++){
Pc[i] = fork();
if (Pc[i] == 0){
printf(" child");
sem_wait(&sem[i]);
printf("Experiment was a success!");
}
if (Pc[i]>0){
printf("Parent");
}
}
for (i =0; i<=argc-2; i++){
if (Pc[i] > 0)
count++;
}
for (i= 0; i<=3; i++){
if ( count == argc-2){
sem_post(&sem[i]);
}
}
}
nameofprogram 1 2
prints: Parent
Child
Parent
Child

You need to read the man page for sem_init(). The type of semaphore you are creating right now is not shared across processes. This requires a non-trivial change to your program, because you also need to set up shared memory. Refer to this question for a lengthy explanation of how to make your program work.

When a program calls fork, a new process is created with a new exact copy of the memory space. This mean that sem in your child process is not the same as sem in your parent process. So, when you call sem_post, you child process can not be notified of the change and get out of the wait function.
To solve this, you have different possibilities:
Create a shared memory which can be read by all your processes and create this semaphore in this shared memory, as already suggested.
Use named semaphores with sem_open. This kind of semaphore can be shared across different processes as it work like a file handle. This seems to be an easier way if you only need a shared semaphore (example here). You will have to generate a unique name for each semaphore in your array (may be only one semaphore on which you call sem_post multiple times would be enough for your use).
Keep your semaphores and use threads instead of processes (but I guess your homework is about processes so this may not be an option for you)

Related

Can a fork child determine whether it is a fork or a vfork?

Within the child process, is there any way that it determine whether it was launched as a fork with overlay memory, or a vfork with shared memory?
Basically, our logging engine needs to be much more careful (and not log some classes of activity) in vfork. In fork it needs to cooperate with the parent process in ways that it doesn't in vfork. We know how to do those two things, but not how to decide.
I know I could probably intercept the fork/vfork/clone calls, and store the fork/vfork/mapping status as a flag, but it would make life somewhat simpler if there was an API call the child could make to determine its own state.
Extra marks: Ideally I also need to pick up any places in libraries that have done a fork or vfork and then called back into our code. And how that can happen? At least one of the libraries we have offers a popen-like API where a client call-back is called from the fork child before the exec. Clearly the utility of that call-back is significantly restricted in vfork.
All code not specifically designed to work under vfork() doesn't work under vfork().
Technically, you can check if you're in a vfork() child by calling mmap() and checking if the memory mapping was inherited by the parent process under /proc. Do not write this code. It's a really bad idea and nobody should be using it. Really, the best way to tell if you're in a vfork() child or not is to be passed that information. But here comes the punchline. What are you going to do with it?
The things you can't do as a vfork() child include calling fprintf(), puts(), fopen(), or any other standard I/O function, nor malloc() for that matter. Unless the code is very carefully designed, you're best off not calling into your logging framework at all, and if it is carefully designed you don't need to know. A better design would most likely be log your intent before calling vfork() in the first place.
You ask in comments about a library calling fork() and then back into your code. That's already kind of bad. But no library should ever ever call vfork() and back into your code without being explicitly documented as doing so. vfork() is a constrained environment and calling things not expected to be in that environment really should not happen.
A simple solution could use pthread_atfork(). The callbacks registered with this service are triggered only upon fork(). So, the 3rd parameter of the function, which is called in the child process right after the fork, could update a global variable. The child can check the variable and if it is modified, then it has been forked:
/*
Simple program which demonstrates a solution to
make the child process know if it has been forked or vforked
*/
#include <pthread.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pid_t forked;
void child_hdl(void)
{
forked = getpid();
}
int main(void)
{
pid_t pid;
pthread_atfork(0, 0, child_hdl);
pid = fork();
if (pid == 0) {
if (forked != 0) {
printf("1. It is a fork()\n");
}
exit(0);
}
// Father continues here
wait(NULL);
pid = vfork();
if (pid == 0) {
if (forked != 0) {
printf("2. It is a fork()\n");
}
_exit(0);
}
// Father continues here
wait(NULL);
return 0;
}
Build/execution:
$ gcc fork_or_vfork.c
$ ./a.out
1. It is a fork()
I came across kcmp today, which looks like it can answer the basic question - i.e. do two tids or pids share the same VM. If you know they represent forked parent/child pids, this can perhaps tell you if they are vfork()ed.
Of course if they are tids in the same process group then they will by definition share VM.
https://man7.org/linux/man-pages/man2/kcmp.2.html
int syscall(SYS_kcmp, pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2);
KCMP_VM
Check whether the processes share the same address space.
The arguments idx1 and idx2 are ignored. See the
discussion of the CLONE_VM flag in clone(2).
If you were created by vfork, your parent will be waiting for you to terminate. Otherwise, it's still running. Here's some very ugly code:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
void doCheck()
{
char buf[512];
sprintf(buf, "/proc/%d/wchan", (int) getppid());
int j = open(buf, O_RDONLY);
if (j < 0) printf("No open!\n");
int k = read(j, buf, 500);
if (k <= 0) printf("k=%d\n", k);
close(j);
buf[k] = 0;
char *ptr = strstr(buf, "vfork");
if (ptr != NULL)
printf("I am the vfork child!\n");
else
printf("I am the fork child!\n");
}
int main()
{
if (fork() == 0)
{
doCheck();
_exit(0);
}
sleep(1);
if (vfork() == 0)
{
doCheck();
_exit(0);
}
sleep(1);
}
This is not perfect, the parent might be waiting for a subsequent vfork call to complete.

Semaphore example in C

I am trying to make a simple semaphore example in C in which, having two while loops, will produce this outcome without threads, using two diferrent processes :
abcd
abcd
abcd
abcd
Since I cannot use pthreads, I tried to make the common signal() and wait() methods but for some reasons, I get an error in the wakeup call inside my signal method.
#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>
wait(sem_t *s)
{
s=s-1;
if (s<0)
block(); // add process to queue
}
signal(sem_t *s)
{
s=s+1;
if (s<=0)
wakeup(p); // remove process p from queue
}
init(sem_t *s , int v)
{
s=v;
}
void main(void)
{
int i;
// place semaphore in shared memory
sem_t *child_sem = mmap(NULL,sizeof(*child_sem),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
sem_t *parent_sem = mmap(NULL,sizeof(*parent_sem),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
init(child_sem, 1); // create child semaphore
init(parent_sem, 1); // create parent semaphore
if (fork())
{
for (i = 0; i < 10; i++)
{
if (wait(child_sem) < 0)
perror("sem_wait");
printf("ab");
if (signal(parent_sem) < 0)
perror("sem_post");
sleep(1); // required to maintain thread order
}
}
else
{
for (i = 0; i < 10; i++)
{ // parent starts waiting
if (wait(parent_sem) < 0)
perror("sem_wait");
printf("cd\n");
if (signal(child_sem) < 0)
perror("sem_post");
}
}
}
Output:
[Error] In function 'signal':
[Error] 'p' undeclared (first use in this function)
The thing is that how could I enter a process p inside the wakeup call?
Should I use a pid=fork() inside a method?
Should I use an extra argument in signal method but what would it be like? pid p ?
If I remove the p argument from wakeup, then variables like PROT_READ become undeclared for some reason.
P.S. The code is from this site.
I will not write the the whole thing but here is a better way to solve this.
Use 2 semaphores.
Run the first process when semaphore number 1 is high
Run the second process when semaphore number 2 is high
At the starting of the critical section of 1st process, make 2nd semaphore low so that the resource can not be used by the 2nd process
At the end of the critical section of the 1st process, make the 2nd semaphore = 1 and 1st semaphore = 0
Do exactly opposite for the second process, i.e., stating sem1 = 0, ending sem1 = 1, sem2 = 0.
This may solve the problem. Never use signal use sigaction instead.

Share POSIX semaphore among multiple processes

I need to create two child processes each of which calls execvp ater being forked, and the executables share POSIX semaphores between them.
Do I need to create a shared memory or just implement named semaphores?
I got two answers from the following links:
Do forked child processes use the same semaphore?
How to share semaphores between processes using shared memory
But I am confused about how to proceed in the implementation.
Do I need to create a shared memory or just implement named
semaphores?
Either approach will work. Pick one and go with it - though I personally prefer named semaphores because you don't have to deal with memory allocation and with setting up the shared memory segments. The interface for creating and using named semaphores is way more friendly, in my opinion.
With named semaphores, in your example scenario, here's what happens:
You create and initialize the semaphore in the parent process with sem_open(3). Give it a well-known name that the child processes will know; this name is used to find the semaphore in the system.
Close the semaphore in the parent, since it won't be using it.
Fork and execute
Unlink the semaphore with sem_unlink(3). This must be done exactly once; it doesn't really matter where (any process that has a reference to the semaphore object can do it). It is ok to unlink a semaphore if other processes still have it open: the semaphore is destroyed only when all other processes have closed it, but keep in mind that the name is removed immediately, so new processes won't be able to find and open the semaphore.
The child processes call sem_open(3) with the well-known name to find and obtain a reference to the semaphore. Once a process is done with the semaphore, you need to close it with sem_close(3).
Below is an example of what I just described. A parent process creates a named semaphore, and forks + executes 2 child processes, each of which finds and opens the semaphore, using it to synchronize between each other.
It assumes that the parent forks and executes the ./sem_chld binary. Keep in mind that a name for a semaphore must begin with a forward slash, followed by one or more characters that are not a slash (see man sem_overview). In this example, the semaphore's name is /semaphore_example.
Here's the code for the parent process:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#define SEM_NAME "/semaphore_example"
#define SEM_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
#define INITIAL_VALUE 1
#define CHILD_PROGRAM "./sem_chld"
int main(void) {
/* We initialize the semaphore counter to 1 (INITIAL_VALUE) */
sem_t *semaphore = sem_open(SEM_NAME, O_CREAT | O_EXCL, SEM_PERMS, INITIAL_VALUE);
if (semaphore == SEM_FAILED) {
perror("sem_open(3) error");
exit(EXIT_FAILURE);
}
/* Close the semaphore as we won't be using it in the parent process */
if (sem_close(semaphore) < 0) {
perror("sem_close(3) failed");
/* We ignore possible sem_unlink(3) errors here */
sem_unlink(SEM_NAME);
exit(EXIT_FAILURE);
}
pid_t pids[2];
size_t i;
for (i = 0; i < sizeof(pids)/sizeof(pids[0]); i++) {
if ((pids[i] = fork()) < 0) {
perror("fork(2) failed");
exit(EXIT_FAILURE);
}
if (pids[i] == 0) {
if (execl(CHILD_PROGRAM, CHILD_PROGRAM, NULL) < 0) {
perror("execl(2) failed");
exit(EXIT_FAILURE);
}
}
}
for (i = 0; i < sizeof(pids)/sizeof(pids[0]); i++)
if (waitpid(pids[i], NULL, 0) < 0)
perror("waitpid(2) failed");
if (sem_unlink(SEM_NAME) < 0)
perror("sem_unlink(3) failed");
return 0;
}
Note that sem_unlink(3) is called after both children terminate; although this is not required, if it was called before there would be a race condition between the parent process unlinking the semaphore and both child processes starting up and opening the semaphore. In general, though, you can unlink as soon as you know that all required processes have opened the semaphore and no new processes will need to find it.
Here's the code for sem_chld, it's just a small toy program to show the usage of a shared semaphore:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define SEM_NAME "/semaphore_example"
#define ITERS 10
int main(void) {
sem_t *semaphore = sem_open(SEM_NAME, O_RDWR);
if (semaphore == SEM_FAILED) {
perror("sem_open(3) failed");
exit(EXIT_FAILURE);
}
int i;
for (i = 0; i < ITERS; i++) {
if (sem_wait(semaphore) < 0) {
perror("sem_wait(3) failed on child");
continue;
}
printf("PID %ld acquired semaphore\n", (long) getpid());
if (sem_post(semaphore) < 0) {
perror("sem_post(3) error on child");
}
sleep(1);
}
if (sem_close(semaphore) < 0)
perror("sem_close(3) failed");
return 0;
}
You can eliminate the need to keep the semaphore name synchronized between the two source files by defining it in a common header file and including it in the code for each program.
Note that error handling is not ideal in this example (it's merely illustrative), there is a lot of room for improvement. It's just there to make sure you don't forget to do proper error handling when you decide to change this example to suit your needs.
Shared memory approach will also work here, only thing here is parent process has to initialise the shared memory.
There seems one bug in this code instead of two child, parent function will fork 3 child process here. There should be break statement inside
if (pids[i] == 0) {
if (execl(CHILD_PROGRAM, CHILD_PROGRAM, NULL) < 0) {
perror("execl(2) failed");
exit(EXIT_FAILURE);
}
break; //this is required
}

posix semaphore trouble

I supposed that my program should work like this:
1) initializing unnamed semaphore with value = 0
the second value for sem_init(..) is 1 so as it said in MAN the semaphore is shared between processes
2) creating child, child waits until semaphore value becomes 1
parent process increases the value of semaphore so the child should exit now
but it doesn't exit really, so that is the problem
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
pid_t child;
void child_proc(sem_t* sem) {
sem_wait(sem);
printf("OK\n");
}
void parent_proc(sem_t* sem) {
sem_post(sem);
sleep(2);
int status;
waitpid(child, &status, 0);
}
int main(int argc, char* argv[]) {
sem_t sem;
sem_init(&sem, 1, 0);
child = fork();
if (0 == child) {
child_proc(&sem);
return 0;
}
parent_proc(&sem);
return 0;
}
The problem is that both processes have a local (not shared) copy of the semaphore structure and changes in one process won't reflect to the other process.
As the man page also says, if you want to share semaphores across processes, not only do you need to pass a non-zero value to the second argument of sem_init, but the sem_t structure also needs to exist in an area of shared memory. In your example program, it exists on the stack, which is not shared.
You can have shared memory by using a common file mapping (with mmap) or with shm_open, notably.

Only one process must execute a code portion at a time

I am sorry I am repeating a question https://stackoverflow.com/questions/5687837/monitor-implementation-in-c but not getting a solution as yet. I have probably asked the question incorrectly.
Say I have a code portion B. A parent process spawns a number of child processes to execute code B but I would like only one process to be inside code portion B at a time. How can I do it in C on Linux platform?
Thanks for your help
An edit. Not threads but process.
You want a mutex.
pthread_mutex_t mutexsum;
pthread_mutex_init(&mutexsum, NULL);
pthread_mutex_lock (&mutexsum);
// Critical code
pthread_mutex_unlock (&mutexsum);
If you are serious about it being multiple processes instead of multiple threads, the mutex needs to be stored in a shared memory segment.
So what you want is to have exactly one child running at any point of time, then why spawn all the children processes all at once?
When a child process ends, a SIGCHLD is issued, you can write your own handler for this signal and call spawn from the handler. Then you have one new child process created when one perishes -- only one child process running. Below is a hack (useless, just for demo) to achieve this:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
void spawn(void){
pid_t child_pid=fork();
if(child_pid > 0){
printf("new child created by %d !\n",getpid());
sleep(1);
}else if(child_pid == 0){
printf("child %d created !\n",getpid());
}else{
exit(EXIT_FAILURE);
}
}
void handler(int sigval){
spawn();
}
int main(void){
signal(SIGCHLD,handler);
spawn();
return 0;
}

Resources