I make program which exec 2 times this code. 2 process enter to semaphore and stuck(HERE comment). Why it happen and how to fix it?
sem_t *sem = sem_open(SEM_NAME, O_RDWR);
if (sem == SEM_FAILED) {
perror("sem_open(3) failed");
exit(EXIT_FAILURE);
}
int j = atoi(argv[1]);
int i;
for (i = 0; i < 2; i++) {
printf("%i\n",getpid() );
//HERE!!!!!
if (sem_wait(sem) < 0) {
perror("sem_wait(3) failed on child");}
printf("PID %ld acquired semaphore\n", (long) getpid());
if (sem_post(sem) < 0) {
perror("sem_post(3) error on child");}
printf("wysz\n");
sleep(1);
}
semcl(sem);
return 0;
You should create the semaphore using this
sem_open(SEM_NAME, O_RDWR,0777, 1);
to set the starting value of the semaphore to 1.
Related
The program consists of 2 parts (i was asked to use pipe):
A. manager - that creates processes that will help him calculate how many instances of a particular char are in the file.
B. Count - Calculates how many instances there are in the file and returns the pipe to the manager.
Moreover, In each program I changed the behavior of SIGPIPE, and changed the behavior I desired.
in the manager.c:
for(i = 0; i < len_sym; i++){
...
if (pipe(pipe_fds + (2 * i)) == -1) {
perror("ERROR : Failed creating pipe");
exit(EXIT_FAILURE);
}
if ((curr_child = fork()) == 0){ //son
dup2(pipe_fds[2*i + 1], STDOUT_FILENO);
close(pipe_fds[2*i + 1]);
close(pipe_fds[2*i + 0]);
execvp(child_args[0], child_args);
}
else { //parent
if (curr_child == -1){
exit(EXIT_FAILURE);
}
close(pipe_fds[2*i + 1]); // close writerfd
child_pids[i] = curr_child;
printf("%d son created with pid %d\n", i + 1, child_pids[i]);
// if (i == 1) {
// kill(curr_child, SIGPIPE);
// }
}
}
for(i = 0; i < len_sym; i++){
curr_child = waitpid(child_pids[i], &exit_code, 0);
printf("exit code %d\n", exit_code);
printf("child pid %d\n", curr_child);
if (curr_child == -1 || 256 == exit_code) {
exit(EXIT_FAILURE);
}
if (WIFEXITED(exit_code)) {
int bytes_read;
while ((bytes_read = read(pipe_fds[i*2 + 0], buff, BUFF_SIZE)) > 0) {
buff[bytes_read] = '\0';
printf("%s", buff);
}
if (bytes_read == -1) {
perror("ERROR : Failed reading from fifo");
close(pipe_fds[i*2 + 0]);
exit(EXIT_FAILURE);
}
close(pipe_fds[i*2 + 0]);
child_pids[i] = 0;
}
}
handling SIGPIPE in manager.c
void my_signal_handler(int signum) {
switch (signum) {
case SIGPIPE:
printf("SIGPIPE for Manager process %d. Leaving\n", getpid());
for (int i = 0; i < len_sym; i++) {
if ((child_pids != NULL) && child_pids[i]) {
kill(child_pids[i], SIGTERM);
}
}
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
void register_signal_handlin() {
struct sigaction new_action;
memset(&new_action, 0, sizeof(new_action));
new_action.sa_handler = my_signal_handler;
if (0 != sigaction(SIGPIPE, &new_action, NULL)) {
exit(EXIT_FAILURE);
}
}
in the count.c:
for (j = 0; j < file_length; j++){
if (*temp++ == c){
counter++;
}
}
sleep(10);
if (argc > 4){
sprintf(buff, "Process %d finishes. Symbol %c. Instances %d.\n", getpid(), c, counter);
int buff_len = strlen(buff);
int bytes_written;
while ((bytes_written = write(writerfd, p, buff_len)) > 0) {
p += bytes_written;
buff_len -= bytes_written;
}
if (bytes_written == -1) {
perror("PROCESS ERROR : Failed writing to fifo");
close(writerfd);
return EXIT_FAILURE;
}
close(writerfd);
}
handling SIGPIPE in count.c
void my_signal_handler(int signum) {
switch (signum) {
case SIGPIPE:
printf("SIGPIPE for process %d. Symbol %c. Counter %d.\n", getpid(), c, counter);
exit(EXIT_FAILURE);
case SIGTERM:
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
void register_signal_handling() {
struct sigaction new_action;
memset(&new_action, 0, sizeof(new_action));
new_action.sa_handler = my_signal_handler;
if (0 != sigaction(SIGPIPE, &new_action, NULL)) {
exit(EXIT_FAILURE);
}
if (0 != sigaction(SIGTERM, &new_action, NULL)) {
exit(EXIT_FAILURE);
}
}
So in fact I run the manger program, and at the same time opens a new terminal, and from it sends kill -13 to a particular process.
the problems:
In the manager I get an exit code of 256. Why?
The WIFSIGNALED flag does not turn on, although I have sent a signal to the process.
The return from the waitpid function is not -1, but the process number I sent kill -13 from the second terminal.
I tried to send kill to one of the children from the manager and for some reason he activates the signal handler of the manager rather than the child's signal handler.
I am in the process of learning OS, so I will be happy for any help.
The child process is another C program run with execlp. The machine is Unix. I know the child process can access the process table with execlp("ps", "ps", NULL) but I can't figure out how it can determine its sibling.
Even though the processes are asynchronous, I know that the sibling process will be running.
Is it possible for a child process to get the PID of its siblings?
Without talking with the parent using sort of a protocol, this is not possible in a portable manner. On some systems it might not even be possible at all.
yes, it is possible. I am attaching c code for this. Here I have taken 4 children and all are sharing their pid's.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define NUM_CHILDREN 4
/* Entry point for the child processes */
int child_main(int pipe_read_end) {
pid_t my_pid = getpid();
/* Read child pids from pipe */
int child_pids[NUM_CHILDREN];
unsigned int bytes_read = 0;
while (bytes_read < sizeof(child_pids)) {
ssize_t result = read(pipe_read_end, ((unsigned char *) child_pids) + bytes_read, sizeof(child_pids) - bytes_read);
if (result < 0) {
perror("error reading from pipe");
return 1;
} else if (result == 0) {
fprintf(stderr, "unexpected end of file\n");
return 1;
} else {
bytes_read += result;
}
}
close(pipe_read_end);
/* Do something useful with these child pids */
for (int i = 0; i < NUM_CHILDREN; i++) {
printf("Child %d received sibling pid %d\n", my_pid, child_pids[i]);
}
return 0;
}
/* Entry point for the parent process. */
int main() {
int child_pids[NUM_CHILDREN];
int pipe_write_ends[NUM_CHILDREN];
for (int i = 0; i < NUM_CHILDREN; i++) {
/* Create the pipe for child i */
int pipefd[2];
if (pipe(pipefd)) {
perror("error creating pipe");
return 1;
}
int pipe_read_end = pipefd[0];
int pipe_write_end = pipefd[1];
/* Fork child i */
pid_t child_pid = fork();
if (child_pid < 0) {
perror("error forking");
return 1;
} else if (child_pid == 0) {
printf("Child %d was forked\n", getpid());
close(pipe_write_end);
return child_main(pipe_read_end);
} else {
printf("Parent forked child %d\n", child_pid);
close(pipe_read_end);
pipe_write_ends[i] = pipe_write_end;
child_pids[i] = child_pid;
}
}
/* Send pids down the pipes for each child */
for (int i = 0; i < NUM_CHILDREN; i++) {
unsigned int bytes_written = 0;
while (bytes_written < sizeof(child_pids)) {
ssize_t result = write(pipe_write_ends[i], ((unsigned char *) child_pids) + bytes_written, sizeof(child_pids) - bytes_written);
if (result < 0) {
perror("error writing to pipe");
return 1;
} else {
bytes_written += result;
}
}
close(pipe_write_ends[i]);
}
/* Wait for children to exit */
for (int i = 0; i < NUM_CHILDREN; i++) {
if (waitpid(child_pids[i], 0, 0) < 0) {
perror("error waiting for child");
return 1;
}
}
}
This is my first question so I apologize if I'm omitting anything important. So I've been working on an assignment that handles piping via forking. My code is pretty messy, littered with printf statements so I see what's going on.
I've looked around online and I think I get the idea of how to handle piping, but the problem I'm having is that my code skips dup2() on any file descriptor except inFD and outFD.
Here's the code for my function. Also, from what I understand, my teacher made a macro called CHK which checks for errors. If there is an error (such as dup2 returning -1), it'll terminate with a print to stderr.
My includes, global variables and myhandler() for signal
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <math.h>
#include <signal.h>
// Function calls
void parse(char *w, char **ptrArray, char *inArray, char *outArray, int *pipeArray);
int flagHandler(char **ptrArray, char *inArray, char *outArray);
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray);
// Global Variables
const int STORAGE = 254;
const int MAXITEM = 100;
int inFD; // file descriptor for <
int outFD; // file descriptor for >
int complete = 0; // for sighandler
int readDes = 0;
int writeDes = 1;
int numPipes = 0;
int status;
int forCounter = 0;
int fildes[4];
int pipeIndex = 0;
// MetaChar flags
int lessthanSign = 0; // < flag
int greaterthanSign = 0; // > flag
int firstChildFlag = 0;
int lastChildFlag = 0;
void myhandler(int signum)
{
complete = 1;
}
My main function
int main()
{
char s[STORAGE]; // array of words
char *newargv[MAXITEM];
char inArray[STORAGE]; // for <
char outArray[STORAGE]; // for >
int firstCheck;
int pidBackground; // holds value from fork(), used for background calls
struct stat st; // for stat(), checks if file exists
// dynamic array based on numPipes
// first child doesn't use this array, as it uses newargv[0] and newargv
// only the middle children and last child use this array, hence 10
int *pipeArray = malloc(10 * sizeof(int));
int numLoops = 0;
int i = 0;
signal(SIGTERM, myhandler);
for(;;)
{
// Reset flags here
lessthanSign = 0;
greaterthanSign = 0;
pipeSign = 0;
firstChildFlag = 0;
lastChildFlag = 0;
pipeIndex = 0;
parse(s, newargv, inArray, outArray, pipeArray);
pipeHandler(newargv, inArray, outArray, pipeArray);
wait(NULL);
fflush(NULL);
} // end for
printf("Entering killpg; numLoops = %d\n", numLoops);
killpg(getpid(), SIGTERM);
printf("p2 terminated.\n");
exit(0);
} // end main
Main calls parse which fills in newargv[]. It also fills in inArray[] and outArray[] with the string immediately after a < and > respectively. When detecting a pipe sign, it puts a null on newargv[], as well as putting a value in pipeArray[] for indexing the executable's name in newargv. I omitted the parse() and flagHandler() calls to keep it minimal.
My parseHandler() function
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray)
{
pid_t firstChild;
pid_t firstChildBackground;
pid_t middleChild;
pid_t lastChild;
pid_t lastChildBackground;
int i = 0; // plain integer for for loops
printf("Initializing pipes\n");
//pipe(fildes);
//pipe(fildes + 2);
for (i = 0; i < (2*numPipes); i+=2)
{
printf("pipe initializing; i is %d\n", i);
if (pipe(fildes + i) < 0)
{
perror("pipe initialization failed");
exit(EXIT_FAILURE);
}
}
fflush(stdout);
if ((firstChild = fork()) < 0)
{
perror("First child's fork failed!");
exit(EXIT_FAILURE);
}
printf("firstChild pid = %d\n", getpid());
if (firstChild == 0)
{
if (firstChildFlag == 1)
{
printf("inFD = open...\n");
inFD = open(inArray, O_RDONLY);
printf("Doing dup2 inFD\n");
if (dup2(inFD, STDIN_FILENO) < 0)
{
perror("First child's < dup2 failed");
exit(EXIT_FAILURE);
}
}
printf("doing dup2 fildes[writeDes]\n");
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("First child's dup2 failed");
exit(EXIT_FAILURE);
}
printf("*****doing dup2 fildes[writeDes] was a success!\n");
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (firstChildFlag == 1)
{
lessthanSign = 0;
firstChildFlag = 0;
if (close(inFD) < 0)
{
perror("close inFD failed");
exit(EXIT_FAILURE);
}
}
writeDes += 2;
printf("About to execvp first child\n");
if (execvp(ptrArray[0], ptrArray) < 0)
{
perror("execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((middleChild = fork() < 0))
{
perror("Middle child's fork failed");
exit(EXIT_FAILURE);
}
printf("middleChild pid = %d\n", getpid());
if (middleChild == 0)
{
if (dup2(fildes[readDes], STDIN_FILENO) < 0)
{
perror("Middle child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("Middle child's dup2 on writing failed");
exit(EXIT_FAILURE);
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
readDes += 2;
writeDes += 2;
if (execvp(ptrArray[pipeArray[0]], ptrArray + pipeArray[0]) < 0)
{
perror("Middle child's execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((lastChild = fork() < 0))
{
perror("Last child's fork failed");
exit(EXIT_FAILURE);
}
printf("lastChild pid = %d\n", getpid());
if (lastChild == 0)
{
if (dup2(fildes[readDes], STDOUT_FILENO) < 0)
{
perror("Last child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (lastChildFlag == 1)
{
outFD = open(outArray, O_CREAT | O_RDWR, 0400 | 0200);
if (dup2(outFD, STDOUT_FILENO) < 0)
{
perror("Last child's > dup2 failed");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (lastChildFlag == 1)
{
greaterthanSign = 0;
lastChildFlag = 0;
if (close(outFD) < 0)
{
perror("close on outFD failed");
exit(EXIT_FAILURE);
}
}
printf("Execvp last child\n");
if (execvp(ptrArray[pipeArray[1]], ptrArray + pipeArray[1]) < 0)
{
perror("Last child's execvp failed");
exit(EXIT_FAILURE);
}
printf("Last child execvp finished\n");
}
}
}
// Only the parent gets here
printf("Only the parent should be here\n");
printf("My pid is %d\n", getpid());
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
for (;;)
{
pid_t pid;
if (pid = wait(NULL) < 0)
{
perror("wait failed");
exit(EXIT_FAILURE);
}
if (pid == lastChild)
{
printf("Parent is waiting for lastChild\n");
break;
}
}
printf("Parent finished waiting. Returning...\n");
return 0;
}
I did pipe(fildes) before any fork, so that all children and a parent have their copy. Therefore, I must close all file descriptors in each child (after dup2 but before execvp) and the parent. The parent will then wait until it gets the pid of lastChild.
With a lot of printf statements, I have found that no child does the dup2() command (except for dup2(inFD...) and dup2(outFD...) when the flags are appropriate). There is also no error printed.
I printed out my (char) newargv[] and my (int) pipeArray[] and they contain the correct values. It seems to be just the dup2 problem, and I have absolutely no idea what's going wrong with it.
I made a simple text file called test2 containing
ls | sort | cat someString
Where someString is just a file with some text. With all the print statements in the pipeHandler() function my output is:
EDIT: I fixed a couple typos I had. I forgot to lace an extra set of parenthesis on 3 ifs, if ((firstChild = fork()0 < 0)
I now have an infinite loop as the parent is waiting for the lastChild's pid. Here's the output:
Initializing pipes
numpipes = 2
pipe initializing; i is 0
pipe initializing; i is 2
firstChild pid = 20521
firstChild pid = 20522
doing dup2 fildes[writeDes]
middleChild pid = 20521
middleChild pid = 20523
lastChild pid = 20521
Only the parent should be here
My pid is 20521
lastChild pid = 20524
<infinite loop>
I'm still clueless though as to what's going on or what's potentially stopping the child.
#MarkPlotnick you're right! It's not that dup2 isn't executing or anything. Because I did dup2(fildes[1], STDOUT_FILENO), all print statements will be piped.
I fixed the typo mentioned as well. I tried my teacher's test file
< input1 cat|>your.outputc tr a-z A-Z | tr \ q
Which should result with a file called your.outputc. It does, and the contents are input1 with the effects of tr. However, I also have the printf statements at the top of this file.
I assumed the dup2 wasn't working because no printf statement followed, unlike it did in dup2(inFD, STDIN_FILENO), but that's probably because it was STDIN.
My code should be executing the start_hydrogen and start_carbon functions several times but only outputs to the console from execution of one thread and then the program hangs. I think I may be incorrectly starting my threads. I am new to C so let me know if additional information is needed. Note that the this line is reached output is printed.
#include "main.h"
void *start_hydrogen(void *);//executes hydrogen.c
void *start_carbon(void *);//executes carbon.c
struct threadInfo {
int threadId;
};
struct threadInfo hydrogenIDs[NUM_H];
struct threadInfo carbonIDs[NUM_C];
int main() {
int semid, shmid;//semaphore memory id, shared memory id
unsigned short seminit[NUM_SEMS];//used to initialize semaphores
struct common *shared;//pointer to shared data structure
union semun semctlarg;//used to initialize semaphores
pthread_t hydrogen[NUM_H];
pthread_t carbon[NUM_C];
pthread_attr_t attr;
void *exit_status;
//Creating a set of attributes to send to the threads
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
//get semaphore memory id
if ((semid = semget(SEMKEY, NUM_SEMS, IPC_CREAT|0777)) < 0) {
perror("semget");
exit(EXIT_FAILURE);
}
printf("THE PROGRAM IS STARTING\n\n");
seminit[MUTEX] = 1;//initialize mutex semaphore count to 1
seminit[SH] = 0;//initialize hyrdrogen semaphore count to 0
seminit[SC] = 0;//initialize carbon semaphore count to 0
semctlarg.array = seminit;//set control array
//apply initialization
if ((semctl(semid, NUM_SEMS, SETALL, semctlarg)) < 0) {
perror("semctl");
exit(EXIT_FAILURE);
}
//get shared memory id
if ((shmid = shmget(SHMKEY, 1*K, IPC_CREAT|0777)) < 0) {
perror("shmget");
exit(EXIT_FAILURE);
}
//retrieve pointer to shared data structure
if ((shared = (struct common *)shmat(shmid, 0, 0)) < 0) {
perror("shmat");
exit(EXIT_FAILURE);
}
//initialize shared data structure variables
shared->waiting_H = 0;
shared->waiting_C = 0;
int retVal;//used to check return value of fork()
// spawn 20 Hydrogens
for (int i=0; i<NUM_H; i++) {
// if ((retVal = fork()) == 0) {
// hydrogen();
// fflush(stdout);
// printf("New Hydrogen process created\n");
// fflush(stdout);
// } else if (retVal < 0) {
// perror("fork");
// exit(EXIT_FAILURE);
// }
hydrogenIDs[i].threadId = i;
retVal = pthread_create(&hydrogen[i], &attr, start_hydrogen, (void*) &hydrogenIDs[i]);
if (retVal != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
printf("this line reached\n");
// spawn 5 Carbons
for (int i=0; i<NUM_C; i++) {
// if ((retVal = fork()) == 0) {
// carbon();
// fflush(stdout);
// printf("New Hydrogen process created\n");
// fflush(stdout);
// } else if (retVal < 0) {
// perror("fork");
// exit(EXIT_FAILURE);
// }
carbonIDs[i].threadId = i;
retVal = pthread_create(&carbon[i], &attr, start_carbon, (void*) &carbonIDs[i]);
if (retVal != 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
//wait for all car processes to finish
// for (int i = 0; i < 25; ++i) {
// if (wait(0) < 0) {
// perror("wait");
// exit(EXIT_FAILURE);
// }
// }
//Wait for all the threads to finish
for(int i = 0; i < NUM_C; i++)
{
pthread_join(carbon[i], &exit_status);
}
for(int i = 0; i < NUM_H; i++)
{
pthread_join(hydrogen[i], &exit_status);
}
printf("All atoms have crossed!\n");
//delete semaphores
if (semctl(semid, NUM_SEMS, IPC_RMID, 0) < 0) {
perror("semctl");
exit(EXIT_FAILURE);
}
//delete shared memory
if (shmctl(shmid, IPC_RMID, 0) < 0) {
perror("shmctl");
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
Original start_carbon() and start_hydrogen() functions
void *start_carbon(void* arg) {
execl("carbon", "carbon", 0);
perror("execl");
exit(EXIT_FAILURE);//if exec returns there was an error
}
void *start_hydrogen(void* arg) {
execl("hydrogen", "hydrogen", 0);
perror("execl");
exit(EXIT_FAILURE);//if exec returns there was an error
}
Modified start_hydrogen() and start_carbon() functions
After receiving feedback about the inappropriateness of using execl(), I changed the start_hydrogen() and start_carbon() functions to:
void *start_hydrogen(void* arg) {
struct common *shared;//pointer to shared data structure
int semid, shmid;//semaphore memory id, shared memory id
int pid = getpid();
//get semaphore memory id
if ((semid = semget(SEMKEY, NUM_SEMS, 0777)) < 0) {
perror("semget");
exit(EXIT_FAILURE);
}
//get shared memory id
if ((shmid = shmget(SHMKEY, 1*K, 0777)) < 0) {
perror("shmget");
exit(EXIT_FAILURE);
}
//get pointer to shared data structure
if ((shared = (struct common *)shmat(shmid, 0, 0)) < 0) {
perror("shmat");
exit(EXIT_FAILURE);
}
// acquire lock on mutex before accessing shared memory
semWait(semid, MUTEX);
fflush(stdout);
printf("Hydrogen atom, pid %d, arrives at barrier\n", pid);
printf("Currently %d Hydrogens and %d Carbons waiting\n", shared->waiting_H + 1, shared->waiting_C);
fflush(stdout);
// if enough C and H is waiting, continue past barrier
if (shared->waiting_H >= 3
&& shared->waiting_C >= 1) {
// release 3 H
for (int i=0; i < 3; i++) {
semSignal(semid, SH);
}
shared->waiting_H -= 3;
semSignal(semid, SC); // release 1 C
shared->waiting_C -= 1;
fflush(stdout);
printf("\nHello from %d, 1 CH4 molecule has xed the barrier\n\n", pid);
fflush(stdout);
// release lock on mutex
semSignal(semid, MUTEX);
} else {
// not enough C or H is waiting, so wait at barrier
shared->waiting_H += 1;
// relaese lock on mutex
semSignal(semid, MUTEX);
semWait(semid, SH);
}
pthread_exit(NULL);
}
void *start_carbon(void* arg) {
struct common *shared;//pointer to shared data structure
int semid, shmid;//semaphore memory id, shared memory id
int pid = getpid();
//get semaphore memory id
if ((semid = semget(SEMKEY, NUM_SEMS, 0777)) < 0) {
perror("semget");
exit(EXIT_FAILURE);
}
//get shared memory id
if ((shmid = shmget(SHMKEY, 1*K, 0777)) < 0) {
perror("shmget");
exit(EXIT_FAILURE);
}
//get pointer to shared data structure
if ((shared = (struct common *)shmat(shmid, 0, 0)) < 0) {
perror("shmat");
exit(EXIT_FAILURE);
}
// acquire lock on mutex before accessing shared memory
semWait(semid, MUTEX);
fflush(stdout);
printf("Hydrogen atom, pid %d, arrives at barrier\n", pid);
printf("Currently %d Hydrogens and %d Carbons waiting\n", shared->waiting_H + 1, shared->waiting_C);
fflush(stdout);
// if enough C and H is waiting, continue past barrier
if (shared->waiting_H >= 3
&& shared->waiting_C >= 1) {
// release 3 H
for (int i=0; i < 3; i++) {
semSignal(semid, SH);
}
shared->waiting_H -= 3;
semSignal(semid, SC); // release 1 C
shared->waiting_C -= 1;
fflush(stdout);
printf("\nHello from %d, 1 CH4 molecule has xed the barrier\n\n", pid);
fflush(stdout);
// release lock on mutex
semSignal(semid, MUTEX);
} else {
// not enough C or H is waiting, so wait at barrier
shared->waiting_H += 1;
// relaese lock on mutex
semSignal(semid, MUTEX);
semWait(semid, SH);
}
pthread_exit(NULL);
}
From the man page for execl(),
The exec() family of functions replaces the current process image with a new process image.
and
The exec() functions only return if an error has occurred.
If you want to use execl() to call external programs, you should fork() the parent process first to allow the parent process to continue running. Note in that case, the threads really won't do what you want.
I was trying to connect daemons (group of daemons without a leader) with main process as in title, the problem is that i have to send statement from each daemon(which are supporting SIGUSR1 signal) to main process, but i don' t even know how to do that, in my code i used mkfifo, but it's not working at all..
here is the main process source:
int main(int argc, char* argv[])
{
pid_t pid;
int i;
int n = atoi(argv[1]);
char c, message[255];
if(argc!=2){
printf("please insert one parametr\n");
return -1;
}
int fd = open("pipe", O_RDONLY);
if (fd == -1) {
perror("Failed open fifo to read");
return EXIT_FAILURE;
}
for( i = 0; i < n; i++) {
pid=fork();
if (pid==0){
printf("daemon created..\n");
}
else{
execl("daemons", "daemons", argv[1], NULL);
while(1){
sleep(2);
read(fd, message, c);
printf("P received: %s\n", message);
close(fd);
//read(fd[0], message, sizeof(message));
}
}
}
return 0;
}
and here is some source code in which i create daemons:
int fd = open("pipe", O_WRONLY);
if (fd < 0){
perror("cannot open fifo: ");
return EXIT_FAILURE;
}
if ( getppid() == 1 )
return 0;
/* Creating daemon */
pid[n] = fork();
if (pid[n] < 0)
exit(EXIT_FAILURE);
if (pid[n] > 0)
exit(EXIT_SUCCESS);
/* Setting leader of session */
sid = setsid();
if (sid < 0){
exit(EXIT_FAILURE);
}
/* fork one more time to make children
to have an opportunity to destroy
session leader */
for ( i = 0; i < n; i++){
pid[i] = fork();
if(pid[i] < 0){
printf("filed to fork...\n");
exit(EXIT_FAILURE);
}
if(pid[i]==0){
while(1){
sleep(2);
printf("Demon[%d]: My ID in pipe.%d\n", i+1, getpid());
signal(SIGUSR1, sigHandler);
write(fd, "Hi\n", strlen("Hi\n"));
close(fd);
}
}
chdir(".");
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
file = fopen("log_file.txt", "w+");
fclose(file);
umask(027);
}
at least i' m not sure about that i am creating daemons in good way..
And where i should put signal, which can be later executed?
Do you have any suggestions?