shared memory producer consumer in C - c

I have to implement a producer-consumer problem via shared memory and semaphores. It should takes input from input.txt file and save it to output.txt file. Process of saving information should be showed in terminal. I have a problem with, I guess, synchronization. When I call fork() and then execl() producer.c file inside, the program seems to be not responding. producer(at least) was working before, but during modifying some lines of code it stopped working and I can't solve it. Here's the piece of code:
#include <stdio.h> // main.c
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>
#include "semaphore.h"
#include "memory.h"
#define SIZE 10
typedef struct cyclicalBuf
{
int size;
char bufor[SIZE];
} cyclicalBuf;
int main(int argc, char *argv[])
{
if(argc != 1)
{
perror("Need no arguments!");
exit(1);
}
int semid;
int memoryID;
int key;
key = semGetKey('A');
semid = semCreate(key, 2); // 2 sem made
setVal(semid, 0, SIZE);
setVal(semid, 1, 0);
memoryID = memoryCreate('A', sizeof(cyclicalBuf));
pid_t pid;
pid = fork();
switch(pid)
{
case -1:
perror("fork() error in producer section");
exit(2);
break;
case 0:
execl("./producer", "./producer", NULL);
perror("execl() error in producer section");
exit(3);
break;
default:
break;
}
sleep(1);
switch(pid)
{
case -1:
perror("fork() error in consumer section");
exit(4);
break;
case 0:
execl("./consumer", "./consumer", NULL);
perror("execl() error in consumer section");
exit(5);
break;
default:
break;
}
int i;
for(i = 0; i < 2; i++)
{
if(wait(0) < 0 )
{
perror("wait() error [main.c]");
}
}
semDelete(semid, 2);
memoryDelete(memoryID);
return 0;
}
#include <stdio.h> // producer.c
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include "memory.h"
#include "semaphore.h"
#define SIZE 10
typedef struct cyclicalBuf
{
int size;
char bufor[SIZE];
} cyclicalBuf;
void producer()
{
FILE *fp;
int i;
int semid;
int memoryID;
cyclicalBuf * buf;
char c;
if((fp = fopen("./input.txt", "r")) == NULL)
{
perror("fopen() error [producer]");
exit(1);
}
int key;
key = semGetKey('A');
semid = semCreate(key, 2); y
memoryID = memoryAccess('A');
buf = (cyclicalBuf *)memoryLink(memoryID);
printf("Producer: ");
for(i = 0; (c = fgetc(fp)) != EOF; i++)
{
semRelease(semid, 0);
usleep(rand()%5555);
buf->bufor[i%SIZE] = c;
buf->size++;
semAcquire(semid, 1);
printf(" %c", c);
}
if(fclose(fp) == EOF)
{
perror("fclose() error [producer]");
exit(2);
}
memoryUnlink(buf);
}
int main(int argc, char *argv[])
{
if(argc != 1)
{
perror("Need no arguments!");
exit(3);
}
srand(time(NULL));
producer();
return 0;
}
#include <stdio.h> // consumer.c
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/sem.h>
#include "memory.h"
#include "semaphore.h"
#define SIZE 10
typedef struct cyclicalBuf
{
int size;
char bufor[SIZE];
} cyclicalBuf;
void consumer()
{
FILE *fp;
int c_cnt = 0;
int i = 0;
int semid;
int memoryID;
cyclicalBuf * buf;
char c;
if((fp = fopen("./output.txt", "w")) == NULL)
{
perror("fopen() error [consumer]");
exit(1);
}
int key;
key = semGetKey('A');
semid = semCreate(key, 2);
memoryID = memoryAccess('A');
buf = (cyclicalBuf *)memoryLink(memoryID);
printf("Consumer: ");
while(!((semctl(semid, 0, GETVAL) == SIZE) && (c_cnt == buf->size)))
{
semRelease(semid, 1);
usleep(rand()%5555);
c = buf->bufor[i%SIZE];
semAcquire(semid, 0);
fputc(c, fp);
printf(" %c", c);
i++;
c_cnt++;
}
if(fclose(fp) == EOF) //
{
perror("fclose() error [consumer]");
exit(2);
}
memoryUnlink(buf); //
}
int main(int argc, char *argv[])
{
if(argc != 1)
{
perror("Need no arguments!");
exit(3);
}
srand(time(NULL));
consumer();
return 0;
}
I can provide semaphore and shared memory functions if needed.
OUTPUT:
./main
| --> this is just blinking cursor, nothing happens

Related

Getting bad address when I fork?

So I have three files: Pellets.c, Fish.c, and SwimMill.c. SwimMill calls Pellets and Fish, which should fork. However, when I try to fork Pellets, i get an error saying "Pellet fork failed: Bad Address". Anyone know what the problem is?
include.h
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#define SHM_SIZE 1000
int shmid;
int *shm;
pid_t fish;
pid_t pellet;
void attachSharedMemory() {
key_t key = ftok("SwimMill.c", 'b'); //generate random key
shmid = shmget(key, SHM_SIZE, IPC_CREAT|0666);
shm = shmat(shmid, NULL, 0);
}
SwimMill.c
// Uses both fish and pellets, 30 seconds, then print it out
// Create pellets at random intervals, from 0x80
// Eating --> Get rid of most significant bit
// Use shared memory for fish and pellet position only
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "include.h"
#define SHM_SIZE 1000
void printGrid(int*);
void handler(int);
void killProgram(pid_t, pid_t, int*, int);
pid_t fish;
pid_t pellet;
int main(int argc, char* argv[]) {
int timer = 0;
attachSharedMemory(); // from include.h
signal(SIGINT, handler);
// Initializing the shared memory to prevent segmentation fault
// for (int i = 0; i < SHM_SIZE; i++){
// shm[i] = -1;
// }
srand(time(NULL));
fish = fork();
if (fish == -1) {
perror("Fish fork failed1");
exit(1);
} else if (fish == 0) {
execv("Fish", argv);
perror("Fish exec failed");
exit(1);
}
while(timer <= 30){
pellet = fork();
if (pellet == -1) {
perror("Pellet Fork failed1");
exit(1);
} else if (pellet == 0) {
execv("Pellets", argv);
perror("Pellets Fork failed");
exit(1);
}
printGrid(shm);
sleep(1);
printf("Timer: %d\n", timer);
timer++;
}
killProgram(fish, pellet, shm, shmid);
getchar(); // Pause consol
return 0;
}
void printGrid(int* shm) {
int row = 10;
int column = 10;
char (*stream)[row][column]; //2D Dimensional array, fish can only move last row of 2d
//Initializing grid first
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
(*stream)[i][j] = '~';
}
}
printf("Fish: %d \n", shm[0]);
printf("Shm2 is: %d \n", shm[1] );
for (int k = 1; k < 20; k++) {
(*stream)[shm[k]/10][shm[k]%10] = 'O'; // pellets
}
(*stream)[shm[0]/10][shm[0]%10] = 'Y'; // Fish
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
printf("%c ", (*stream)[i][j]);
}
printf("\n");
}
}
void killProgram(pid_t fish, pid_t pellet, int *shm, int shmid) {
kill(fish,SIGUSR1);
kill(pellet, SIGUSR1);
sleep(5);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
printf("Program finished! \n");
}
void handler(int num ) {
kill(fish,SIGUSR1);
kill(pellet, SIGUSR1);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
perror(" Interrupt signal is pressed!! \n");
exit(1);
}
Pellets.c
// Multiple pellets
//Process ID, position, eaten/misse
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "include.h"
#define SHM_SIZE 1000
void handler(int);
void eatPellet();
void missPellet();
int main(int argc, char* argv[]) {
signal(SIGINT, handler);
attachSharedMemory();
srand(time(NULL));
int i = 1; // 1 - 19 are pellets
for (; i < 20; i++) {
int pelletPosition = rand() % 9 ; // random number from 0 - 9
if (shm[i] == -1){
// printf("hello %d \n", pelletPosition);
shm[i] = pelletPosition;
}
break;
}
while(1) {
printf("helloasd %d \n", shm[i]);
printf("i: %d \n", i);
if (shm[i] < 90) {
shm[i] += 10;
}
else if (shm[i] == shm[0]) {
eatPellet();
printf("Position: %d\n", shm[i] );
break;
// EATEN and KILL
}
else {
// KIll process, terminate
missPellet();
printf("Position: %d\n", shm[i] );
break;
}
// printf("%d\n",shm[i] );
i++;
sleep(1);
}
shmdt(shm);
return 0;
}
void handler(int num) {
shmdt(shm);
exit(1);
}
I looked at other stack overflow questions, and it seems that they problems because they didn't terminate with a NULL? I think the problem lies inside Pellets.c, but I can't seem to figure it out. Thanks.

when i pass string from child process to parent process via shared memory

i am trying to pass a string from a child process to parent process and the parent process has to capitalise that string from parent process ,but when the parent process receives the string i get segmentation fault when i use strlen. It is like parent process doesnt recognize the string that both parent and child use.
This is my program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/wait.h>
#define SEM1KEY 1234
#define SEM2KEY 4321
#define SHM1KEY 5678
#define SHM2KEY 8765
#define SHM1SIZE sizeof(struct in_ds)
#define SHM2SIZE sizeof(struct out_ds)
typedef struct in_ds{
pid_t pid;
char *line;
}in_ds;
typedef struct out_ds{
pid_t pid;
char *cap_line;
}out_ds;
union semun{
int val;
struct semid_ds *buff;
unsigned short *array;
};
int main(int argc, char *argv[])
{
int n=5,k=5;
int semid[2], shmid[2];
int i, j, result, pid_match=0, overall_pid_match=0;
union semun arg;
struct sembuf oparray[2] = {{0,-1,0},{0,1,0}};
char buffer[]="abcde", *c_line;
pid_t pid;
in_ds *inds;
out_ds *outds;
FILE *fp;
////////////////////shm//////////////////
shmid[0] = shmget((key_t)1234,SHM1SIZE,IPC_CREAT|0600);
if(shmid[0]==-1)
{
perror("shmget failed!");
return -1;
}
shmid[1] = shmget((key_t)4321,SHM2SIZE,IPC_CREAT|0600);
if(shmid[1]==-1)
{
perror("shmget failed!");
return -1;
}
inds = (in_ds*)shmat(shmid[0],(in_ds*)0,0);
outds = (out_ds*)shmat(shmid[1],(out_ds*)0,0);
if(inds==NULL || outds==NULL)
{
printf("shmat failed!");
return -1;
}
printf("ok1");
////////////////////sem///////////////////
semid[0] = semget(SEM1KEY,1,IPC_CREAT|0600);
if(semid[0]==-1)
{
perror("semget failed!");
return -1;
}
semid[1] = semget(SEM2KEY,1,IPC_CREAT|0600);
if(semid[1]==-1)
{
perror("semget failed!");
return -1;
}
arg.val = 0;
if(semctl(semid[0],0,SETVAL,arg)==-1)
{
perror("semaphore initialization failed!");
return -1;
}
arg.val = 1;
if(semctl(semid[1],0,SETVAL,arg)==-1)
{
perror("semaphore initialization failed!");
return -1;
}
outds->pid = 0;
inds->pid = 0;
for(i=0; i<n; i++)
{
pid = fork();
if(pid>0)
{
continue; //parent
}else if(pid == 0){
break; //child
}else{
printf("fork failed!"); //ERROR
return -1;
}
}
if(pid>0) //C process
{
for(i=0; i<k+1; i++)
{
semop(semid[1],&oparray[0],1); //down(sem2)
if(inds->pid!=0)
{
c_line = malloc((strlen(inds->line)+1)*sizeof(char));
strcpy(c_line,inds->line);
free(inds->line);
j=0;
while(c_line[j]!='\0')
{
c_line[j] += -32;
j++;
}
outds->pid = inds->pid;
outds->cap_line = malloc((strlen(c_line)+1)*sizeof(char));
strcpy(outds->cap_line,c_line);
free(c_line);
}
semop(semid[0],&oparray[1],1); //up(sem1)
}
}else{
fp = fopen("textfile","r");
for(i=0; i<k; i++)
{
printf("ok2");
semop(semid[0],&oparray[0],1); //down(sem1)
if(outds->pid == 0)
{}
else if(outds->pid == -1)
{
fclose(fp);
exit(pid_match);
}else{
if(outds->pid == getpid())pid_match++;
printf("Line:%s , pid:%d, mypid:%d",outds->cap_line,outds->pid,getpid());
free(outds->cap_line);
}
inds->line = malloc((strlen(buffer)+1)*sizeof(char));
strcpy(inds->line,buffer);
inds->pid = getpid();
semop(semid[1],&oparray[1],1);
}
}
semctl(semid[0],0,IPC_RMID,0);
semctl(semid[1],0,IPC_RMID,0);
shmdt(inds);
shmdt(outds);
shmctl(shmid[0],IPC_RMID,NULL);
shmctl(shmid[1],IPC_RMID,NULL);
}
when i debug i see:
Program received signal SIGSEGV, Segmentation fault.
strlen () at ../sysdeps/x86_64/strlen.S:106
106 ../sysdeps/x86_64/strlen.S: No such file or directory.
c_line = malloc((strlen(inds->line)+1)*sizeof(char));
this is the second time parent process is running
and it gets a string which is inds->line

individual char extraction in c while using messages and msgsnd

This is bugging me for days.
The problem is my not so good understanding of pointers and addresses in c so i hope someone will be able to help me out.
I need to pass some strings as input parameters and create as much producer processes + one consumer process.
Producers should take the string apart and send each letter as message to queue. At the end it should send NULL("").
The consumer should wait for messages and print them out.
The whole code and output is below. By looking at the output i'd say that the problem is somewhere in the producer. To be more precise it is in the first line of te for loop but i can not get it right.
manager.c - This is the main program that operates processes
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/msg.h>
int main( int argc, char *argv[], char *envp[] ) {
printf("Starting %d processes \n", argc);
putenv("MSG_KEY=12345");
for (int i = 1; i < argc; i++) {
printf("argv[%d] = %s \n", i, argv[i]);
pid_t producer = fork();
if (producer == 0) {
printf("producer pid - %d\n", getpid());
execl("./producer", "producer", argv[i], NULL);
}
}
pid_t consumer = fork();
if (consumer == 0) {
printf("consumer pid - %d\n", getpid());
execl("./consumer", "consumer", NULL);
exit(0);
} else {
printf("manager pid - %d\n", getpid());
wait(NULL);
}
int status;
while(waitpid(consumer, &status, 0) == -1);
printf("DONE consumer\n");
printf("DONE manager\n");
return 0;
}
producer.c
/*
** writes to message queue
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msgbuf {
long mtype;
char mtext[1];
};
int main( int argc, char *argv[], char *envp[] ) {
struct my_msgbuf buf;
int msqid;
key_t key = atoi(getenv("MSG_KEY"));
if ((msqid = msgget(key, 0600 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
buf.mtype = getpid();
// I believe the error is in this for loop or to be more precise in the first line of the for loop.
// takes the first argument and sends characters in separate messages
for (int i = 0; i < strlen(argv[1]); ++i) {
char c = argv[1][i];
strcpy(buf.mtext, &c);
printf ("Sending -%s-\n", buf.mtext);
if (msgsnd(msqid, (struct msgbuf *)&buf, strlen(buf.mtext)+1, 0) == -1)
perror("msgsnd");
}
// send NULL at the end
memcpy(buf.mtext, "", strlen("")+1);
if (msgsnd(msqid, (struct msgbuf *)&buf, strlen("")+1, 0) == -1)
perror("msgsnd");
return 0;
}
consumer.c
/*
** reads from message queue
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msgbuf {
long mtype;
char mtext[1];
};
int main( int argc, char *argv[], char *envp[] ) {
struct my_msgbuf buf;
int msqid;
key_t key = atoi(getenv("MSG_KEY"));
if ((msqid = msgget(key, 0600 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
int flag = 0;
int wait_counter = 0;
while (wait_counter < 10) {
msgrcv(msqid, (struct msgbuf *)&buf, sizeof(buf)-sizeof(long), 0, flag);
if (errno == ENOMSG){
wait_counter++;
printf ("Sleaping for one second...zzzZZZzzz...%d\n", wait_counter);
usleep(1000 * 1000);
} else {
printf("Received:\n\ttype: -%ld- \n\tchar: -%s- \n", buf.mtype, buf.mtext);
int compare = strcmp(buf.mtext, "");
if(compare == 0){
printf("NULL received\n");
flag = IPC_NOWAIT;
} else {
flag = 0;
}
wait_counter = 0;
}
errno = 0;
}
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
} else {
printf("Message queue removed\n");
}
return 0;
}
Output - i have to give you the screenshot here because c/p deletes the problem and everything looks ok
Any help will be much appreciated! Thank you!
Error when used as suggested in the #sergeya answer below
*buf.mtext = c;
Your problem (one of them, at least) is here:
char c = argv[1][i];
strcpy(buf.mtext, &c);
strcpy() will try to copy as many characters as there are until nul-terminator '\0' is encountered, starting from c. You need to copy one character exactly, so you just need
*buf.mtext = c;
As i said, the problem was in the producer inside the for loop. I will put the change here. Hope it helps anyone with the similar problem.
#SergeyA gave me excellent clue where the problem is so i switched from "strcpy" to "memcpy" and i have copied just the first character and not the nul-terminator.
Also i have changed the "strlen" to "sizeof" and removed the +1.
Producer.c
...
for (int i = 0; i < strlen(argv[1]); ++i) {
char c = argv[1][i];
memcpy(buf.mtext, &c, sizeof(&c)+1);
printf ("Sending -%c-\n", buf.mtext);
if (msgsnd(msqid, (struct msgbuf *)&buf, sizeof(buf.mtext), 0) == -1)
perror("msgsnd");
}
...

How to implement a kill command in my own shell

I'm trying to create my shell in C, but I don't know how to implement the kill function.
I can't use the command kill(), I want to create my own function by insert for exemple " k process_pid ".
Here my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define maxarg 20
void CtrlC(int sig);
void execute(char *argv[]);
char getargs(int *argcp, char *argv[], int max);
int main () {
signal(SIGINT,CtrlC);
char *argv[maxarg+1];
int argc;
while (1) {
printf(">");
if(!getargs(&argc, argv, maxarg) || argc == 0) {
continue;
}
if(strncmp(argv[0], "exit", 4) == 0) {
printf("Program completed.\n");
exit(0);
}
execute(argv);
}
}
char getargs(int *argcp, char *argv[], int max){
static char cmd[100];
char *cmdp;
int i;
if(gets(cmd) == NULL)
exit(0);
cmdp = cmd;
for(i=0; i<=max; i++){
if((argv[i] = strtok(cmdp, " \t")) == NULL)
break;
cmdp = NULL;
}
if(i > max){
printf(">Too many arguments!\n");
return -1;
}
*argcp = i;
return(1);
}
void execute(char *argv[]) {
int i;
switch (fork()) {
case -1:
printf(">Error in the creation of the process.\n");
return;
case 0:
execvp(argv[0], argv);
printf(">Can't execute.\n");
perror(">execvp");
exit(1);
default:
if(wait(NULL) == -1)
perror(">Wait");
}
}
void CtrlC (int sig) {
signal(sig, SIG_IGN);
printf("\n>To exit digit 'exit'.\n>");
signal(SIGINT,CtrlC);
fflush(stdout);
}
Exactly what you did with the exit command, you just have to:
test for !strncmp(argv[0],"k",1)
then decode the pid with sscanf(argv[1],"%d",&pid)
then kill it with kill(pid,SIGTERM) (or any other signal you want)

Global variable not staying set, maybe caused by fork()

I'm trying to write a very very simple unix shell in C, and I have the basics of what I need working, except support for a history command. I have a global 2D char array that holds the history of all entered commands. Commands are added before the fork() system call, and I was originally printing out the value of the history global array after strings were added, and they were printing out correctly, so I'm not sure why it doesn't print out when the command "history" is used at the shell.
Thank to anyone who takes a look.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "myhistory.h"
int BUFFER_SIZE = 1024;
char history[100][80];
int command_index = 0;
int main(int argc, char *argv[]){
int status = 0;
int num_args;
pid_t pid;
while(1){
char *buffer_input, *full_input;
char command[BUFFER_SIZE];
char *args[BUFFER_SIZE];
printf("myshell> ");
buffer_input = fgets(command, 1024, stdin);
full_input = malloc(strlen(buffer_input)+1);
strcpy(full_input, buffer_input);
if (command_index >= 100) {
command_index = 0;
}
strncpy(history[command_index], full_input, strlen(full_input) + 1);
command_index += 1;
parse_input(command, args, BUFFER_SIZE, &num_args);
//check exit and special command conditions
if (num_args==0)
continue;
if (!strcmp(command, "quit" )){
exit(0);
}
if(!strcmp(command, "history")){
int i;
fprintf(stderr,"%d\n",(int)pid);
for(i = 0; i < command_index; i++){
fprintf(stdout, "%d: %s\n",i+1,history[command_index]);
}
continue;
}
errno = 0;
pid = fork();
if(errno != 0){
perror("Error in fork()");
}
if (pid) {
pid = wait(&status);
} else {
if( execvp(args[0], args)) {
perror("executing command failed");
exit(1);
}
}
}
return 0;
}
void parse_input(char *input, char** args,
int args_size, int *nargs){
char *buffer[BUFFER_SIZE];
buffer[0] = input;
int i = 0;
while((buffer[i] = strtok(buffer[i], " \n\t")) != NULL){
i++;
}
for(i = 0; buffer[i] != NULL; i++){
args[i] = buffer[i];
}
*nargs = i;
args[i] = NULL;
}
Change:
fprintf(stdout, "%d: %s\n",i+1,history[command_index]);
to:
fprintf(stdout, "%d: %s\n",i+1,history[i]);

Resources