Caught in an infinite loop solving reader writer prob - infinite-loop

I am working on reader-writer problem. Algorithm wise, i believe the solution is ok. The only problem that I am facing is opening multiple readers/writer windows using xterm. When I run the program it goes into an infinite loop and it crashed the whole system. It also open multiple xterm windows. It might be silly and simple, but I just don't seem to be able to figure out why? I've been thinking about this since yesterday. How do i fix this problem? The suspected area of conflict is highlighted with ** comments...
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <errno.h> /* Errors */
#include <stdio.h> /* Input/Output */
#include <stdlib.h> /* General Utilities */
#include <pthread.h> /* POSIX Threads */
#include <string.h> /* String handling */
#include <semaphore.h> /* Semaphore */
//Global Variablels
int rc = 0;
int wc = 0;
sem_t m1, m2, m3, w, r; //Semphore
int reader() {
sem_wait(&m3);
sem_wait(&r);
sem_wait(&m1);
rc++;
if(rc == 1) sem_wait(&w);
sem_post(&m1);
sem_post(&r);
sem_post(&m3);
system("xterm -e ./read");
//execlp("xterm", "-e", "./ahor2r", NULL);
sem_wait(&m1);
rc--;
if(rc == 0) sem_post(&w);
sem_post(&m1);
return 0;
}
int writer() {
sem_wait(&m2);
wc++;
if(wc == 1) sem_wait(&r);
sem_post(&m2);
sem_wait(&w);
//system("xterm -e ./write"); //writing is performed
execlp("xterm", "-e", "./ahor2w", NULL);
sem_post(&w);
sem_wait(&m2);
wc--;
if(wc == 0) sem_post(&r);
sem_post(&m2);
return 0;
}
int main() {
int ch;
sem_init(&m1, 0, 1);
sem_init(&m2, 0, 1);
sem_init(&m3, 0, 1);
sem_init(&w, 0, 1);
sem_init(&r, 0, 1);
/*****************************************************************************
**********infinite loop*******************************************************/
while(1) {
printf("\n\nEnter your option\n\n1> Create Reader\n2> Create Writer\n 3> Exit\n\t");
scanf("%d", &ch);
if(ch == 1)
switch(fork()) {
case -1:
perror("Cannot fork a new reader process\n");
break;
case 0:
reader();
}
else if (ch == 2)
switch(fork()) {
case -1:
perror("Cannot fork a new reader process\n");
break;
case 0:
writer();
}
else if (ch == 3) {
sem_destroy(&m1);
sem_destroy(&m2);
sem_destroy(&m3);
sem_destroy(&w);
sem_destroy(&r);
return 0;
}
else printf("INVALID OPTION - no action taken\n");
}
/*****************************************************************************
*****************************************************************************/
return 0;
}

You have two big errors:
You don't create your semaphores in shared memory. So each process gets its own copy of the semaphores, which makes no sense.
You don't create process-shared semaphores. The 0 in sem_init means that the semaphores will not be shared between processes. But fork creates new processes.
If pshared has the value 0, then the semaphore is shared between the threads of a process[.] If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)).

Related

Trouble with creating an empty file using C programming language in UNIX environment

I have recently started programming in UNIX environment. I need to write a program which creates an empty file with name and size given in the terminal using this commands
gcc foo.c -o foo.o
./foo.o result.txt 1000
Here result.txt means the name of the newly created file, and 1000 means the size of the file in bytes.
I know for sure that lseek function moves the file offset, but the trouble is that whenever I run the program it creates a file with a given name, however the size of the file is 0.
Here is the code of my small program.
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
int fd;
char *file_name;
off_t bytes;
mode_t mode;
if (argc < 3)
{
perror("There is not enough command-line arguments.");
//return 1;
}
file_name = argv[1];
bytes = atoi(argv[2]);
mode = S_IWUSR | S_IWGRP | S_IWOTH;
if ((fd = creat(file_name, mode)) < 0)
{
perror("File creation error.");
//return 1;
}
if (lseek(fd, bytes, SEEK_SET) == -1)
{
perror("Lseek function error.");
//return 1;
}
close(fd);
return 0;
}
If you aren't allowed to use any other functions to assist in creating a "blank" text file, why not change your file mode on creat() then loop-and-write:
int fd = creat(file_name, 0666);
for (int i=0; i < bytes; i++) {
int wbytes = write(fd, " ", 1);
if (wbytes < 0) {
perror("write error")
return 1;
}
}
You'll want to have some additional checks here but, that would be the general idea.
I don't know whats acceptable in your situation but, possibly adding just the write() call after lseek() even:
// XXX edit to include write
if ((fd = creat(file_name, 0666)) < 0) {
perror("File creation error");
//return 1;
}
// XXX seek to bytes - 1
if (lseek(fd, bytes - 1, SEEK_SET) == -1) {
perror("lseek() error");
//return 1;
}
// add this call to write a single byte # position set by lseek
if (write(fd, " ", 1) == -1) {
perror("write() error");
//return 1;
}
close(fd);
return 0;

Count the running process in AIX by it's name in C

Operating system: IBM AIX 5.3
Compiler: xlc
Hello Everyone
I have a project that using C to process some files using multi-processes. The number of sub-processes are mainly depends on the the number of incoming files and the number of current running processes. I need a reliable method to count on how many sub-processes are running at background.
By comparing the efficiency, directly reading /proc directory may have better performance than invoking popen() to execute $ ps -ef | grep blah.
I wrote a function to read psinfo in /proc/pid/psinfo and compare the arugments.
Pseudo code is as follow:
int count = 0;
dp = opendir("/proc");
while (readdir_r(...))
{
if (dir is not a process)
return -1;
if (dir's owner is not current user)
return -2;
if (failed to open "/proc/[pid]/psinfo")
return -3;
if (failed to read "/proc/[pid]/psinfo")
return -4;
if (process's name matches the given pname)
count += 1;
}
return count;
The function generally runs perfectly at single call. However, it returns -2 or -3 or even wrong counts when embedded in while loop.
The function failed to read the attribute of /proc/pid randomly. It tells No such file or directory.
There is also a small chance to get wrong counts at the end. There seems to be an extra process with certain pid but disappeared when printing the current processes using ps.
I think there is any change were made when reading from sub-directory rapidly after parent directory were being listed.
Is there any thing I made wrong or is there any method to avoid the race condition?
Come extra information about psinfo in AIX
http://www-01.ibm.com/support/knowledgecenter/ssw_aix_53/com.ibm.aix.files/doc/aixfiles/proc.htm%23files-proc?lang=en[233]
Here is the full source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/procfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int countProcess(char *pname)
{
DIR *dir;
int fd;
int pid;
int uid;
int pcounter = 0;
struct psinfo pinfo;
struct dirent entry;
struct dirent *result;
struct stat fsstat;
char path[256];
char process_path[256];
/* Open the /proc directory */
if ((dir = opendir("/proc")) == NULL)
{
return -1;
}
/* Retrieve the current user id */
uid = getuid();
/* Walk through the /proc dir */
for (readdir_r(dir, &entry, &result); result != NULL; readdir_r(dir, &entry, &result))
{
/* See if this is a process, e.g., the dirname is a number
If not, then start off again
*/
if ((pid = atoi(entry.d_name)) == 0)
{
continue;
}
/* Get the attributes of process dir */
snprintf(process_path, sizeof(process_path), "/proc/%s", entry.d_name);
if (stat(process_path, &fsstat) == -1)
{
closedir(dir);
return -2;
}
/* Verify if the process runs by current user
If not, then start off again
*/
if (fsstat.st_uid != uid)
{
continue;
}
/* Open and read from psinfo file */
snprintf(path, sizeof(path), "/proc/%s/psinfo", entry.d_name);
if ((fd = open(path, O_RDONLY)) < 0)
{
close(fd);
closedir(dir);
return -3;
}
if (read(fd, &pinfo, sizeof(pinfo)) < 0)
{
close(fd);
closedir(dir);
return -4;
}
/* String comparison, if same, increase the counter */
if (!strcmp(pinfo.pr_psargs, pname))
{
pcounter++;
}
close(fd);
}
/* returns counter */
closedir(dir);
return pcounter;
}
Update 13/Jan/2015
Thanks to CoreyStup. The race condition can be bypassed by getprocs() function provided in procinfo.h
Here is the code for the solution
#include <stdio.h>
#include <unistd.h>
#include <procinfo.h>
#include <sys/types.h>
int countProcess(const char *pname)
{
struct procsinfo pinfo;
pid_t pid = 0;
uid_t uid;
char args[256];
int index;
int pcounter = 0;
memset(args, 0, sizeof(args));
uid = getuid();
/* Get procsinfo from internal API */
while (0 < getprocs(&pinfo, (int)sizeof(struct procsinfo), NULL, 0, &pid, 1))
{
/* Skip the process that doesn't belong to current user */
if (pinfo.pi_uid != uid)
{
continue;
}
/* Get process arguments */
if (getargs(&pinfo, sizeof(struct procsinfo), args, sizeof(args)) != 0)
{
return -1;
}
/* getargs returns the args list seperated by 0, we need to use space to replace 0 */
for (index = 0; index < 256 - 1 && !(args[index] == 0 && args[index + 1] == 0); index++)
{
if (args[index] == 0)
{
args[index] = ' ';
}
}
if (!strncmp(args, pname, strlen(pname)))
{
pcounter++;
}
}
return pcounter;
}
Try using getprocs(). I find it works better than shelling out with /proc or ps.
I gave an example here: Need help in getting the process name based on the pid in aix

Need explanation MPI_Scatter()

Im trying to do the Monte Carlo problem using MPI were we generate x amount of rand. num between 0 and 1 and then send n-length numbers to each processor. I'm using scatter function but my code doesn't run right, it compiles but it doesn't ask for the input. I dont understand how MPI loops by itself without loops, can some explain this and what is wrong with my code?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "mpi.h"
main(int argc, char* argv[]) {
int my_rank; /* rank of process */
int p; /* number of processes */
int source; /* rank of sender */
int dest; /* rank of receiver */
int tag = 0; /* tag for messages */
char message[100]; /* storage for message */
MPI_Status status; /* return status for */
double *total_xr, *p_xr, total_size_xr, p_size_xr; /* receive */
/* Start up MPI */
MPI_Init(&argc, &argv);
/* Find out process rank */
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
/* Find out number of processes */
MPI_Comm_size(MPI_COMM_WORLD, &p);
double temp;
int i, partial_sum, x, total_sum, ratio_p, area;
total_size_xr = 0;
partial_sum = 0;
if(my_rank == 0){
while(total_size_xr <= 0){
printf("How many random numbers should each process get?: ");
scanf("%f", &p_size_xr);
}
total_size_xr = p*p_size_xr;
total_xr = malloc(total_size_xr*sizeof(double));
//xr generator will generate numbers between 1 and 0
srand(time(NULL));
for(i=0; i<total_size_xr; i++)
{
temp = 2.0 * rand()/(RAND_MAX+1.0) -1.0;
//this will make sure if any number computer stays in the boundry of 0 and 1, doesn't go over into the negative
while(temp < 0.0)
{
temp = 2.0 * rand()/(RAND_MAX+1.0) -1.0;
}
//array set to total random numbers generated to be scatter into processors
total_xr[i] = temp;
}
}
else{
//this will be the buffer for the processors to hold their own numbers to add
p_xr = malloc(p_size_xr*sizeof(double));
printf("\n\narray set\n\n");
//scatter xr into processors
MPI_Scatter(total_xr, total_size_xr, MPI_DOUBLE, p_xr, p_size_xr, MPI_DOUBLE, 0, MPI_COMM_WORLD);
//while in processor the partial sum will be caluclated by using xr and the formula sqrt(1-x*x)
for(i=0; i<p_size_xr; i++)
{
x = p_xr[i];
temp = sqrt(1 - (x*x));
partial_sum = partial_sum + temp;
}
//}
//we will send the partial sums to master processor which is processor 0 and add them and place
//the result in total_sum
MPI_Reduce(&partial_sum, &total_sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
//once we have all of the sums we need to multiply the total sum and multiply it with 1/N
//N being the number of processors, the area should contain the value of pi.
ratio_p = 1/p;
area = total_sum*ratio_p;
printf("\n\nThe area under the curve of f(x) = sqrt(1-x*x), between 0 and 1 is, %f\n\n", area);
/* Shut down MPI */
MPI_Finalize();
} /* main */
In general, its not good to rely on STDIN/STDOUT for an MPI program. It's possible that MPI implementation could put rank 0 on some node other than the node on which you're launching your jobs. In that case you have to worry about forwarding correctly. While this will work most of the time, it's not usually a good idea.
A better way to do things is to have your user input be in a file that the application can read or via command line variables. Those will be much more portable.
I'm not sure what you mean by MPI looping by itself without loops. Maybe you can clarify that comment if you still need an answer there.

Emulating ' find ' command in C

What would be the best way to do this in the C programming language?
find fileName
Look up the POSIX function nftw(). It is designed as a 'new file tree walk' function.
There's a related but not immediately as useful function scandir() which you might use. The selection function might be used to invoke a recursive scan on sub-directories, for example, but nftw() is probably more appropriate.
You could call find from a forked child process and get back find's output from a pipe:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFSIZE 1000
int main(void) {
int pfd[2], n;
char str[BUFSIZE + 1];
if (pipe(pfd) < 0) {
printf("Oups, pipe failed. Exiting\n");
exit(-1);
}
n = fork();
if (n < 0) {
printf("Oups, fork failed. Exiting\n");
exit(-2);
} else if (n == 0) {
close(pfd[0]);
dup2(pfd[1], 1);
close(pfd[1]);
execlp("find", "find", "filename", (char *) 0);
printf("Oups, execlp failed. Exiting\n"); /* This will be read by the parent. */
exit(-1); /* To avoid problem if execlp fails, especially if in a loop. */
} else {
close(pfd[1]);
while ((n = read(pfd[0], str, BUFSIZE)) > 0) {
str[n] = '\0';
printf("%s", str);
}
close(pfd[0]);
wait(&n); /* To avoid the zombie process. */
if (n != 0) {
printf("Oups, find or execlp failed.\n");
}
}
}
That's a complex topic. Have a look at the GNU libc documentation. Then try to scan the current directory using scandir. If that works, you can implement a recursive version, assuming you are talking about the UNIX find command and want to do recursive search for file names.

UNIX IPC C program only parent process can write to file, child not working

I need to use Signal to write UNIX Interprocess communication program in C. I want a parent process and child process to write to a same file.
The result only show parent written text. I can use either BSD or System V. Please help
#include <stdio.h> /* basic I/O routines. */
#include <unistd.h> /* define fork(), etc. */
#include <sys/types.h> /* define pid_t, etc. */
#include <sys/wait.h> /* define wait(), etc. */
#include <signal.h>
int myFlag = 0;
void myHandler(int);
int child_pid;
int main()
{
//oldmask = sigblock(sigmask(SIGUSR1));
sighold(SIGUSR1);
sighold(SIGINT);
/* critical region */
signal (SIGUSR1, myHandler);
sigrelse(SIGUSR1);
sigrelse(SIGINT);
child_pid = fork();
if (child_pid==0) {
for ( ; ; ) {
while(myFlag == 0)
sigpause(0);
sigblock (sigmask(SIGUSR1));
myFlag = 0;
FILE *fp=fopen("test","w");
fwrite("child",1,6,fp);
fclose(fp);
kill(getppid(),SIGUSR1);
}
}
if (child_pid>0){
FILE *fp;
fp=fopen("test","w");
fwrite("parent",1,6,fp);
fclose(fp);
for ( ; ; ) {
while(myFlag == 0)
sigpause(0);
sigblock (sigmask(SIGUSR1));
myFlag = 0;
fp=fopen("test","w");
fwrite("parent",1,6,fp);
fclose(fp);
}
kill(child_pid, SIGUSR1);
//kill ()-child_pid ;
}
exit(0);
}
void myHandler(int sigNo) {
myFlag = 1;
//signal (SIGUSR1, myHandler);
}
You should start by opening the file in append mode rather than write mode:
fp = fopen("test", "a");
That will position the write position of fp at the end of file rather than the beginning. When you open with "w", you truncate the file and start writing from position 0:
w or wb
Truncate to zero length or create file for writing.
Then you might want to think about file locking to keep the two processes from writing to the file at the same time.
Also, your child process writes out the nul terminator:
fwrite("child", 1, 6, fp);
but your parent process doesn't:
fwrite("parent", 1, 6, fp);
That may or may not be your intention but it does look odd.
Your logic is flawed. The parent process does not signal the child process before it waits for the child process to signal it. The child process waits for the parent process to signal it before writing the file and signaling the parent process.
This means after you write the file in the parent both the parent and child are stuck in busy loops waiting for the other one to do something.
Also, while I don't think this is a problem in your code since the call to sigpause(0); should cause the compiler to believe that global variables may have changed and need to be reloaded, in other situations you might want to declare myFlag as volatile int myFlag;. This forces the compiler to read or write its value from memory every time you reference it.
Lastly, of course, your programs will simply re-write over the same bytes repeatedly because you open the files in "w" (write) mode instead of "a" (append) mode.
Here's a program that accomplishes what you want using POSIX standard calls and techniques instead of the old deprecated obsolete calls you were using:
#include <stdio.h> /* basic I/O routines. */
#include <unistd.h> /* define fork(), etc. */
#include <sys/types.h> /* define pid_t, etc. */
#include <sys/wait.h> /* define wait(), etc. */
#include <signal.h>
#include <stdlib.h>
volatile sig_atomic_t myFlag = 0;
void myHandler(int);
int child_pid;
int main()
{
signal (SIGUSR1, myHandler);
child_pid = fork();
if (child_pid==0) {
for ( ; ; ) {
while(myFlag == 0)
;
{
sigset_t oldmask;
sigset_t usr1;
sigemptyset(&oldmask);
sigemptyset(&usr1);
sigaddset(&usr1, SIGUSR1);
sigprocmask(SIG_BLOCK, &usr1, &oldmask);
myFlag = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
FILE *fp=fopen("test","a");
fwrite("child\n",1,6,fp);
fclose(fp);
kill(getppid(),SIGUSR1);
}
}
if (child_pid>0){
FILE *fp;
fp=fopen("test","a");
fwrite("parent\n",1,7,fp);
fclose(fp);
for ( ; ; ) {
kill(child_pid, SIGUSR1);
//kill ()-child_pid ;
while(myFlag == 0)
;
{
sigset_t oldmask;
sigset_t usr1;
sigemptyset(&oldmask);
sigemptyset(&usr1);
sigaddset(&usr1, SIGUSR1);
sigprocmask(SIG_BLOCK, &usr1, &oldmask);
myFlag = 0;
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
fp=fopen("test","a");
fwrite("parent\n",1,7,fp);
fclose(fp);
}
}
exit(0);
}
void myHandler(int sigNo) {
myFlag = 1;
//signal (SIGUSR1, myHandler);
}

Resources