Random core dumps - c

I'm writing a project, in which there are two programs, client and server, client sends a string to server, server process it and then sends it back to the client(there can be multiple clients at the same time, and this is where lies my problem). I'm sending process ID from client in the same string that needs to be processed, server extracts process ID. However I'm getting random Core dumps, which arent consistant. Most of the time it works fine. It happens right before invoking strtol() call in receive_message(...) function.
Server receive_message(...) function:
int receive_message(struct message *x){
int ret_val, z;
ret_val = msgrcv(msg_q_id, x, MAX, 0, 0);
if (ret_val == -1){
if (signal_detection == 1){
exit(0);
}
perror("COULDNT receive a message!");
exit(-1);
} else {
int c = 0;
while (x->mtext[c] != '!'){
++c;
}
int h = c;
char tab[strlen(x -> mtext) - c];
int s = 0;
for (int counter = c + 1; counter < strlen(x->mtext); ++counter){
tab[s++] = x->mtext[counter];
}
printf("\n%s\n", tab);
z = strtol(tab, NULL, 10);
memset((x -> mtext) + h, 0, strlen(x -> mtext) - 1 - c);
printf("message received: %s\n", x -> mtext);
}
return z;
}
Whole server code:
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <signal.h>
#define MAX 255
#define CLIENT 1
#define SERVER 2
int signal_detection = 0;
int msg_q_id;
key_t msg_q_key;
struct message;
void create_queue();
void send_message(struct message *x, int pid);
int receive_message(struct message *x);
void delete_message_q();
void to_upper_case(struct message *x);
void signal_handler(int signum, siginfo_t *info, void *ptr);
struct message{
long int mtype;
char mtext[MAX];
};
int main(){
struct message member_of_message;
struct message *ptr;
struct sigaction sig;
int sig_ret;
ptr = &member_of_message;
sig.sa_sigaction = signal_handler;
sig_ret = sigaction(SIGINT, &sig, NULL);
if (sig_ret == -1){
perror("sigaction fail");
}
create_queue();
while (1){
int pid;
memset(member_of_message.mtext, 0, strlen(member_of_message.mtext));
printf("waiting for message\n");
pid = receive_message(ptr);
to_upper_case(ptr);
printf("After uppering: %s\n", member_of_message.mtext);
send_message(ptr, pid);
sleep(1);
}
}
void create_queue(){
printf("starting to create queue\n");
msg_q_key = ftok(",", 4);
msg_q_id = msgget(msg_q_key, 0700|IPC_CREAT);
if (msg_q_id == -1){
perror("COULDNT create msgq");
exit(-1);
} else {
printf("succesfully created: %d !\n", msg_q_id);
}
}
void send_message(struct message *x, int pid){
int ret_val;
x -> mtype = pid + 1;
wysylanie:
ret_val = msgsnd(msg_q_id, x, strlen(x -> mtext) + 1, 0);
if (ret_val == -1){
if (errno == EAGAIN){
perror("message queue is full!");
goto wysylanie;
}
perror("COULDNT send a message");
exit(-1);
} else {
printf("message sent!\n");
}
}
int receive_message(struct message *x){
int ret_val, z;
ret_val = msgrcv(msg_q_id, x, MAX, 0, 0);
if (ret_val == -1){
if (signal_detection == 1){
exit(0);
}
perror("COULDNT receive a message!");
exit(-1);
} else {
int c = 0;
while (x->mtext[c] != '!'){
++c;
}
int h = c;
char tab[strlen(x -> mtext) - c];
int s = 0;
for (int counter = c + 1; counter < strlen(x->mtext) - 1; ++counter){
tab[s++] = x->mtext[counter];
}
printf("\n%s\n", tab);
z = strtol(tab, NULL, 10);
memset((x -> mtext) + h, 0, strlen(x -> mtext) - 1 - c);
printf("message received: %s\n", x -> mtext);
}
return z;
}
void delete_message_q(){
int ret_val;
ret_val = msgctl(msg_q_id, IPC_RMID, 0);
if (ret_val == -1){
perror("COULDNT remove message queue");
exit(-1);
} else {
printf("message queue deleted!\n");
}
}
void to_upper_case(struct message *x){
for (int counter = 0; counter < strlen(x->mtext); ++counter){
x->mtext[counter] = toupper(x->mtext[counter]);
}
}
void signal_handler(int signum, siginfo_t *info, void *ptr){
signal_detection = 1;
printf("\nReceived a signal!\nstopping iteration\n");
delete_message_q();
}
Client code:
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <pthread.h>
#include <string.h>
#define MAX 255
#define CLIENT 1
#define SERVER 2
#define M_SENT 3
int msg_q_id;
key_t msg_q_key;
struct message;
int pid;
void create_queue();
void *send_message();
void *receive_message(void *arg);
struct message{
long int mtype;
char mtext[MAX];
};
int main(){
struct message member_of_message;
struct message *ptr;
int thread_val;
ptr = &member_of_message;
pthread_t pid1, pid2;
create_queue();
sleep(1);
printf("creating thread1......\n");
thread_val = pthread_create(&pid1, NULL, send_message, NULL);
if (thread_val != 0){
perror("couldnt create thread");
exit(-1);
}
printf("creating thread2......\n");
thread_val = pthread_create(&pid2, NULL, receive_message, ptr);
if (thread_val != 0){
perror("couldnt create thread");
exit(-1);
}
thread_val = pthread_join(pid1, NULL);
if (thread_val != 0){
perror("couldnt create thread");
exit(-1);
}
thread_val = pthread_join(pid2, NULL);
if (thread_val != 0){
perror("couldnt create thread");
exit(-1);
}
}
void create_queue(){
printf("starting creation of a queue\n");
msg_q_key = ftok(",", 4);
msg_q_id = msgget(msg_q_key, 0700|IPC_CREAT);
if (msg_q_id == -1){
perror("COULDNT create msgq");
exit(-1);
} else {
printf("succesfully created: %d !\n", msg_q_id);
}
}
void *send_message(){
int last_val;
struct message member_of_message;
int ret_val;
char rub[10000];
for (int message_counter = 0; message_counter < M_SENT; ++message_counter){
pid = getpid();
member_of_message.mtype = pid;
char arr[MAX];
if (fgets(arr, MAX - 20, stdin) == NULL){
perror("not a single char read, message sent is empty");
}
if (strlen(arr) == 1){
perror("cannot send empty message!");
exit(-1);
}
if (strchr(arr, '\n') == NULL){
perror("Przepelniono komunikat!");
fgets(rub, 10000, stdin);
}
char temp_arr[20];
int sp_retval;
sp_retval = sprintf(temp_arr, "%d", pid);
if (sp_retval == 0){
perror("0 bytes read");
exit(-1);
}
for (int counter = 0; counter < strlen(arr) - 1; ++counter){
member_of_message.mtext[counter] = arr[counter];
last_val = counter;
}
member_of_message.mtext[last_val + 1] = '!';
strcat(member_of_message.mtext, temp_arr);
wysylanie:
ret_val = msgsnd(msg_q_id, (struct message*)&member_of_message, strlen(member_of_message.mtext), 0);
if (ret_val == -1){
if (errno == EAGAIN){
perror("message queue is full!");
goto wysylanie;
}
perror("COULDNT send a message");
exit(-1);
} else {
printf("message sent!, PID: %d \n", pid);
memset(member_of_message.mtext, 0, strlen(member_of_message.mtext));
}
}
}
void *receive_message(void *arg){
int ret_val;
for (int message_counter = 0; message_counter < M_SENT; ++message_counter){
sleep(1);
((struct message*)arg)->mtype = pid + 1;
ret_val = msgrcv(msg_q_id, (struct message*)arg, MAX, ((struct message*)arg)->mtype, 0);
if (ret_val == -1){
perror("COULDNT receive a message!");
exit(-1);
} else {
printf("message received: %s\n", ((struct message*)arg)->mtext);
memset(((struct message*)arg)->mtext, 0, strlen(((struct message*)arg)->mtext));
}
}
}

ret_val = msgsnd(msg_q_id, (struct message*)&member_of_message, strlen(member_of_message.mtext), 0);
This line shows most clearly the problem with this code. You are sending messages that consist of a message type and message text. The size of a message cannot possibly equal the length of the message text because there also needs to be some number of bytes sent to hold the message type.

Related

Can't I send 2 messages with different key with message queue with child-parent IPC in C?

Trying to send 2 different integers with 2 different keys in same function. but lower one doesn't actually work and only show -1 value.
Child is sending 2 messages, and parent receives it.
and parent's printf receives it with msgrcv, and should show its pid and cpu_burst value.
Tried compiling with gcc, but child() still skips while(sunstatus) and go direct to printf and returns 0.
This is my code.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include "msg_cm.h"
#include "runq.h"
#include "waitq.h"
#include "cidq.h"
void timer_handler(int signum) {
int temp = runq[0];
putwtq(temp);
rmvrnq();
}
int child(int key, int quant){
int cpid = getpid();
srand(cpid);
int cpu_burst = rand() % 100 + 6;
int io_burst = rand() % 100 + 1;
msg_sndr(key, cpid);
msg_sndr(cpid, cpu_burst);
int runstatus = 1;
int onoffchk = 0;
while(runstatus) {
if (msg_rcvr(getpid()) > 0) {
onoffchk = 1 - onoffchk;
}
if (onoffchk == 1) {
cpu_burst = cpu_burst - quant;
}
}
printf("Child process terminated.\n");
msg_sndr(5678, 3);
return 0;
}
int main() {
int temp = 500000;
int cnt = 1;
int pid;
int quantum = 5;
int count = 9;
int comp[10];
while(temp > 0) {
msg_rcvr(1234);
temp = temp -1;
}
printf("Parent running: %d\n", getpid());
for (int i = 0; i < 10; i++) {
pid = fork();
if(pid == 0) {
break;
}
else if (pid > 0) {
printf("Child process : %d created.\n", pid);
}
else {
printf("fork() failed!!!");
return -1;
}
}
if(pid == 0) {
child(1234, quantum);
}
else {
int tick = 1;
int end = 10;
struct sigaction sigac;
struct itimerval timer;
struct itimerval stoptimer;
sigac.sa_handler = timer_handler;
sigaction(SIGALRM, &sigac, NULL);
timer.it_value.tv_sec = quantum;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = quantum;
timer.it_interval.tv_usec = 0;
stoptimer.it_value.tv_sec = 0;
stoptimer.it_value.tv_sec = 0;
stoptimer.it_interval.tv_sec = 0;
stoptimer.it_interval.tv_sec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
while(end > 1){
if (msg_rcvr(5678) > 0) {
end--;
setitimer(ITIMER_REAL, &stoptimer, NULL);
setitimer(ITIMER_REAL, &timer, NULL);
}
if (msg_exist(1234) != 2) {
putrnq(msg_rcvr(1234));
}
if (runq[0] == -1) {
printf("%d\tidle\n",tick);
}
else {
printf("%d\tProcess: %d running...\tCPU burst: %d", tick, runq[0], msg_rcvr(runq[0]));
}
tick++;
sleep(1);
}
printf("All childs are terminated.\n");
}
return 0;
}
msg_cm.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgdata {
long int msg_type;
int text;
}message;
int msg_sndr(int key, int num) {
int msgid;
struct msgdata message;
char buf[20];
msgid = msgget((key_t)key, 0666 | IPC_CREAT);
if (msgid == -1) {
printf("error while creating msg q!!!");
return -1;
}
message.msg_type = 1;
message.text = num;
if (msgsnd(msgid, (void *)&message, sizeof(message), 0) == -1) {
printf("msg not sent!!!");
return -1;
}
}
int msg_rcvr(int key) {
int msgid;
struct msgdata message;
long int msg_to_rec = 0;
msgid = msgget((key_t)key, 0666| IPC_CREAT);
if (msgrcv(msgid, (void *)&message, sizeof(message), msg_to_rec, 0 | IPC_NOWAIT) > 0) {
return message.text;
}
else {
return -1;
}
msgctl(msgid, IPC_RMID, 0);
}
int msg_exist(int key) {
int msgid;
msgid = msgid = msgget((key_t)key, 0666| IPC_CREAT);
struct msqid_ds buf;
int rc = msgctl(msgid, IPC_STAT, &buf);
unsigned int msg = (unsigned int)(buf.msg_qnum);
rc = msgctl(msgid, IPC_STAT, &buf);
msg = (uint)(buf.msg_qnum);
if (msg > 0) {
return 1;
}
else {
return 2;
}
}
*all of idq.h
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cburstq[20];
int ccount = 0;
void putidq(int num) {
cburstq[ccount] = num;
ccount++;
}
int rmvidq() {
int tmp = cburstq[0];
for (int tmpnm = 0; tmpnm < ccount; tmpnm++){
cburstq[tmpnm] = cburstq[tmpnm + 1];
}
ccount--;
return tmp;
}

error in msgsnd - msgrcv, I can't view the second string sent

Hi (sorry for my bad English), I'm trying to practice Linux to manipulate message queues in IPC.
I have created a program that allows one process (child 1) to send the message in the queue, while the other process (child 2) reads that message.
this message is defined as a structure composed of two strings (str1 and str2) and a type (long).
The goal that I want to realize and read the two strings but the result is that the program in the reads only one.
Thanks.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct{
long int type;
char str1[255];
char str2[255];
}msg;
void sender(int fd_msg){
msg message;
char *string1 = "Hello";
char *string2 = "World";
strcpy(message.str1,string1);
strcpy(message.str2,string2);
message.type = 1;
if(msgsnd(fd_msg,&message,strlen(message.str1)+1,0) == -1){
printf("Error sending message at message 1 queue %d --> %s\n",errno,strerror(errno));
return;
}
message.type = 2;
if(msgsnd(fd_msg,&message,strlen(message.str2)+1,0) == -1){
printf("Error sending message at message 2 queue %d --> %s\n",errno,strerror(errno));
return;
}
if(printf("Message sent at the queue: %s -- %s\n",message.str1,message.str2) < 0){
printf("Error printing sent messages %d --> %s\n",errno,strerror(errno));
msgctl(fd_msg,IPC_RMID,NULL);
return;
}
return;
}
void receiver(int fd_msg){
msg message;
char string1[255];
char string2[255];
sleep(1);
if(msgrcv(fd_msg,&message,sizeof(message)-sizeof(long int),1,0) == -1){
printf("error reiceiving message type 1 %d --> %s\n",errno,strerror(errno));
return;
}
if(msgrcv(fd_msg,&message,sizeof(message)-sizeof(long int),2 ,0) == -1){
printf("error reiceiving message type2 %d --> %s\n",errno,strerror(errno));
return;
}
if(printf("Message reiceved! : %s -- %s\n",message.str1,message.str2) < 0){
printf("Error printing received message %d --> %s\n",errno,strerror(errno));
msgctl(fd_msg,IPC_RMID,NULL);
return;
}
strcpy(string1,message.str1);
strcpy(string2,message.str2);
//printf("string2: %s\n",messaggio.str2);
return;
}
int main(int argc, char* argv[]){
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt",55);
if((fd_msg = msgget(key_msg,IPC_CREAT | 0770)) == -1){
printf("Error creation message queue %d --> %s\n",errno, strerror(errno));
return -1;
}
if((p1 = fork()) == 0){
//child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1,NULL,0);
if((p2 = fork()) == 0){
//child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2,NULL,0);
msgctl(fd_msg,IPC_RMID,NULL);
return 0;
}
You should send only one message and a length of sizeof(message)-sizeof(long int) just as you do for receiving the message. That's because str1 and str2 have fixed lengths of 255.
You want only one message (that sends the data for both strings in a single message).
As you have it, the "short" payload length that you [should] send is 255 + 5 + 1 and not 5 + 1 + 5 + 1
There are a number of ways to do this:
Send one message with both strings using the full sizeof(msg)
Send one message with full size of str1 but short length of str2
Combine str1 and str2 into a single buffer and [manually] concatenate/split the strings
Use a single buffer and send two messages, one for each string, using just the short length of each string.
Example #1:
Here is the corrected code using the full message size:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct {
long int type;
char str1[255];
char str2[255];
} msg;
void
sender(int fd_msg)
{
msg message;
char *string1 = "Hello";
char *string2 = "World";
strcpy(message.str1, string1);
strcpy(message.str2, string2);
size_t len = sizeof(message) - sizeof(long);
message.type = 1;
printf("Sending length %zu\n",len);
if (msgsnd(fd_msg, &message, len, 0) == -1) {
printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
return;
}
if (printf("Message sent at the queue: %s -- %s\n", message.str1, message.str2) < 0) {
printf("Error printing sent messages %d --> %s\n", errno, strerror(errno));
msgctl(fd_msg, IPC_RMID, NULL);
return;
}
return;
}
void
receiver(int fd_msg)
{
msg message;
char string1[255];
char string2[255];
sleep(1);
ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
if (len == -1) {
printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
return;
}
printf("Received length: %zu\n",len);
if (printf("Message received! : %s -- %s\n", message.str1, message.str2) < 0) {
printf("Error printing received message %d --> %s\n", errno, strerror(errno));
msgctl(fd_msg, IPC_RMID, NULL);
return;
}
strcpy(string1, message.str1);
strcpy(string2, message.str2);
// printf("string2: %s\n",messaggio.str2);
return;
}
int
main(int argc, char *argv[])
{
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt", 55);
if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
return -1;
}
if ((p1 = fork()) == 0) {
// child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) {
// child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2, NULL, 0);
msgctl(fd_msg, IPC_RMID, NULL);
return 0;
}
Here is the program output:
Sending length 512
Message sent at the queue: Hello -- World
Received length: 512
Message received! : Hello -- World
Example #2:
Here is the program using a "short" length for str2:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct {
long int type;
char str1[255];
char str2[255];
} msg;
void
sender(int fd_msg)
{
msg message;
char *string1 = "Hello";
char *string2 = "World";
strcpy(message.str1, string1);
strcpy(message.str2, string2);
size_t len = sizeof(message.str1) + strlen(message.str2) + 1;
message.type = 1;
printf("Sending length %zu\n",len);
if (msgsnd(fd_msg, &message, len, 0) == -1) {
printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
return;
}
if (printf("Message sent at the queue: %s -- %s\n", message.str1, message.str2) < 0) {
printf("Error printing sent messages %d --> %s\n", errno, strerror(errno));
msgctl(fd_msg, IPC_RMID, NULL);
return;
}
return;
}
void
receiver(int fd_msg)
{
msg message;
char string1[255];
char string2[255];
sleep(1);
ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
if (len == -1) {
printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
return;
}
printf("Received length: %zu\n",len);
if (printf("Message received! : %s -- %s\n", message.str1, message.str2) < 0) {
printf("Error printing received message %d --> %s\n", errno, strerror(errno));
msgctl(fd_msg, IPC_RMID, NULL);
return;
}
strcpy(string1, message.str1);
strcpy(string2, message.str2);
// printf("string2: %s\n",messaggio.str2);
return;
}
int
main(int argc, char *argv[])
{
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt", 55);
if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
return -1;
}
if ((p1 = fork()) == 0) {
// child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) {
// child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2, NULL, 0);
msgctl(fd_msg, IPC_RMID, NULL);
return 0;
}
Here is the program output:
Sending length 261
Message sent at the queue: Hello -- World
Received length: 261
Message received! : Hello -- World
Example #3:
Using separate str1 and str2 forces us to send the full size for str1 even if the actual string length is less.
To send a single message that has both strings and sends only the length we need would require combining str1 and str2 into a single buffer (e.g. strs). This requires that we concatenate the two strings into the buffer.
This also requires that the receiver recover the two separate strings.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct {
long int type;
char strs[512];
} msg;
void
sender(int fd_msg)
{
msg message;
char *string1 = "Hello";
char *string2 = "World";
char *cp = message.strs;
strcpy(cp, string1);
cp += strlen(cp) + 1;
strcpy(cp, string2);
cp += strlen(cp) + 1;
size_t len = cp - message.strs;
message.type = 1;
printf("Sending length %zu\n",len);
if (msgsnd(fd_msg, &message, len, 0) == -1) {
printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
return;
}
}
void
receiver(int fd_msg)
{
msg message;
char string1[255];
char string2[255];
sleep(1);
ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
if (len == -1) {
printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
return;
}
printf("Received length: %zu\n",len);
char *cp = message.strs;
strcpy(string1, cp);
cp += strlen(cp) + 1;
strcpy(string2, cp);
cp += strlen(cp) + 1;
printf("string1: %s\n",string1);
printf("string2: %s\n",string2);
return;
}
int
main(int argc, char *argv[])
{
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt", 55);
if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
return -1;
}
if ((p1 = fork()) == 0) {
// child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) {
// child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2, NULL, 0);
msgctl(fd_msg, IPC_RMID, NULL);
return 0;
}
Here is the program output:
Sending length 12
Received length: 12
string1: Hello
string2: World
Example #4:
I'd probably do example #1 and send the full struct length.
Or, I'd use the combined buffer from example #3, but send two separate messages, one for each string:
Here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct {
long int type;
char str[255];
} msg;
void
sendone(int fd_msg,int type,const char *str)
{
msg message;
strcpy(message.str, str);
size_t len = strlen(str) + 1;
message.type = type;
printf("Sending type %ld length %zu\n",message.type,len);
if (msgsnd(fd_msg, &message, len, 0) == -1) {
printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
return;
}
printf("Message sent at the queue: %s\n", message.str);
}
void
sender(int fd_msg)
{
char *string1 = "Hello";
char *string2 = "World";
sendone(fd_msg,2,string2);
sendone(fd_msg,1,string1);
return;
}
ssize_t
recvone(int fd_msg,msg *message)
{
int type = 0;
ssize_t len = msgrcv(fd_msg, message, sizeof(msg) - sizeof(long int), type, 0);
if (len == -1) {
printf("error receiving message %d --> %s\n", errno, strerror(errno));
return len;
}
printf("Received type %ld message of length: %zu\n",message->type,len);
printf("Message received! : %s\n",message->str);
return len;
}
void
receiver(int fd_msg)
{
msg message;
char strings[2][255];
sleep(1);
// deliberately receive messages in any order
for (int imsg = 1; imsg <= 2; ++imsg) {
recvone(fd_msg,&message);
strcpy(strings[message.type - 1],message.str);
}
for (int imsg = 1; imsg <= 2; ++imsg)
printf("receiver: string %d: %s\n",imsg,strings[imsg - 1]);
return;
}
int
main(int argc, char *argv[])
{
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt", 55);
if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
return -1;
}
if ((p1 = fork()) == 0) {
// child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) {
// child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2, NULL, 0);
msgctl(fd_msg, IPC_RMID, NULL);
return 0;
}
Here is the program output:
Sending type 2 length 6
Message sent at the queue: World
Sending type 1 length 6
Message sent at the queue: Hello
Received type 2 message of length: 6
Message received! : World
Received type 1 message of length: 6
Message received! : Hello
receiver: string 1: Hello
receiver: string 2: World

Building semaphores using Mutexes

I'm reading Modern Operating Systems and there's a exercise that asks you to build a counting-semaphore with a binary-semaphore.
I was wondering if I could do it with semaphores & shared memory (C and POSIX IPC).
I'll leave a simplification of my program here.
typedef struct sem {
int semid; /* contains two semaphores with value set to 1, one for the critical region and the other for locking */
int shmid; /* shared counter */
}Sem;
/* the parent process spawns a few child processes and then waits for them */
void child() {
Sem *s;
s = get_sem();
down_sem(s);
printf("working...");
sleep(5);
printf("finished!");
up_sem(s);
}
void down_sem(Sem *s) {
int n;
enter_critical(s); // down to critical region sem
n = get_counter(s);
if (n == 0) {
exit_critical(s); // up to critical region sem
acquire_lock(s); // down to lock sem
} else {
n--;
exit_critical(s); // up to critical region sem
}
}
void up_sem(Sem *s) {
int n;
enter_critical(s);
n = get_counter(s);
n++;
if (n == 1) {
exit_critical(s);
release_lock(s); // up to lock sem
} else {
exit_critical(s);
}
}
But this doesn't work since some processes block in the lock semaphore forever. I'm just now learning these concepts so my design is probably totally off.
I can share the complete code if you wish.
Thanks in advance!
EDIT: requested mre
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/shm.h>
#define NPROC 5
#define SLOTS 2
#define PATH "."
#define SID 'S'
#define SEMN 2
#define SHMID 'M'
#define SHM_SIZE 32
#define CRIT 0
#define LOCK 1
#define UP 1
#define DOWN -1
typedef struct sem {
int shmid;
int semid;
}Sem;
typedef union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
}Args;
void err (char *msg) {
char error[50];
int n;
n = snprintf(error, 50, "[%d] %s", getpid(), msg);
error[n] = 0;
perror(error);
exit(1);
}
int* get_n(Sem *s) {
int *data = NULL;
data = shmat(s->shmid, (void *)0, 0);
if (data == (int *)(-1))
err("get_n shmat");
return data;
}
void dettach_n(int *data) {
if (shmdt(data) == -1)
err("dettach_n shmdt");
}
void enter_crit(Sem *s) {
struct sembuf sb;
sb.sem_num = CRIT;
sb.sem_op = DOWN;
printf("[%d] enter crit\n", getpid());
if (semop(s->semid, &sb, 1) == -1)
err("enter crit");
}
void exit_crit(Sem *s) {
struct sembuf sb;
sb.sem_num = CRIT;
sb.sem_op = UP;
printf("[%d] exit crit\n", getpid());
if (semop(s->semid, &sb, 1) == -1)
err("exit crit");
}
void acquire_lock(Sem *s) {
struct sembuf sb;
sb.sem_num = LOCK;
sb.sem_op = DOWN;
printf("[%d] acquire lock\n", getpid());
if (semop(s->semid, &sb, 1) == -1)
err("acquire lock");
}
void release_lock(Sem *s) {
struct sembuf sb;
sb.sem_num = LOCK;
sb.sem_op = UP;
printf("[%d] release lock\n", getpid());
if (semop(s->semid, &sb, 1) == -1)
err("release lock");
}
int sem_init(Sem *s, int n) {
key_t key;
Args arg;
int *data;
/* sem */
if ((key = ftok(PATH, SID)) == -1) {
return -1;
}
if ((s->semid = semget(key, SEMN, 0600 | IPC_CREAT)) == -1) {
return -1;
}
arg.val = 1;
if (semctl(s->semid, 0, SETVAL, arg) == -1) {
return -1;
}
if (semctl(s->semid, 1, SETVAL, arg) == -1) {
return -1;
}
/* mem */
if ((key = ftok(PATH, SHMID)) == -1) {
return -1;
}
if ((s->shmid = shmget(key, SHM_SIZE, 0664 | IPC_CREAT)) == -1) {
return -1;
}
data = shmat(s->shmid, (void *)0, 0);
if (data == (int *)(-1)) {
return -1;
}
*data = n;
if (shmdt(data) == -1) {
return -1;
}
return 0;
}
int sem_get(Sem *s) {
key_t key;
if ((key = ftok(PATH, SID)) == -1) {
return -1;
}
if ((s->semid = semget(key, SEMN, 0)) == -1) {
return -1;
}
if ((key = ftok(PATH, SHMID)) == -1) {
return -1;
}
if ((s->shmid = shmget(key, SHM_SIZE, 0)) == -1) {
return -1;
}
return 0;
}
int sem_up(Sem *s) {
int *data;
enter_crit(s);
data = get_n(s);
printf("[%d] read %d\n", getpid(), *data);
(*data)++;
if (*data == 1) {
printf("[%d] now is %d\n", getpid(), *data);
dettach_n(data);
exit_crit(s);
release_lock(s);
} else {
exit_crit(s);
}
return 0;
}
int sem_down(Sem *s) {
int *data;
enter_crit(s);
data = get_n(s);
printf("[%d] checked %d\n", getpid(), *data);
if (*data == 0) {
dettach_n(data);
exit_crit(s);
acquire_lock(s);
} else {
(*data)--;
dettach_n(data);
exit_crit(s);
}
return 0;
}
int sem_rm(Sem *s) {
if (semctl(s->semid, 0, IPC_RMID) == -1)
return -1;
if (shmctl(s->shmid, 0, IPC_RMID) == -1)
return -1;
return 0;
}
void child() {
pid_t pid;
Sem s;
pid = getpid();
printf("\x1b[31m[%d] hello!\033[0m\n", pid);
if (sem_get(&s) == -1) {
perror("sem_get");
exit(1);
}
sem_down(&s);
printf("\x1b[32m[%d] working...\033[0m\n", pid);
sleep(5);
printf("\x1b[32m[%d] finishing...\033[0m\n", pid);
sem_up(&s);
printf("\x1b[34m[%d] **child leaving**\033[0m\n", pid);
exit(0);
}
int main() {
Sem s;
int i;
if (sem_init(&s, SLOTS) == -1) {
perror("sem_init");
exit(1);
}
printf("[%d] parent\n", getpid());
for (i = 0; i < NPROC; i++) {
switch(fork()) {
case 0:
child();
case -1:
perror("fork");
exit(1);
}
}
printf("waiting for children...\n");
for (i = 0; i < NPROC; i++)
wait(NULL);
if (sem_rm(&s) == -1) {
perror("sem_rm");
exit(1);
}
printf("good bye!\n");
return 0;
}
The problem was in the up_sem function. It only does an up to the lock sem (release_lock func) if n was previously 0. This is incorrect since it might be several process waiting.
My solution was adding an extra shared memory counting the waiting processes and doing an up to the lock sem when that number is greater than 0.

FIFO doesn't read sometimes in all processes + Process 2 dies when trying to freeze program

How this program should work:
Make 3 processes, P1 is reading line from keyboard, P2 is checking if the line is looking like this - number1+number2+...+number n, P3 is giving me sum of this equation.
This works fine.
The second part is that I have to use Signals+FIFO to either stop(S1-SIGINT), freeze(S2-SIGUSR1) or resume(S3-SIGUSR2) work in this program. One signal should store the info about what signal was called in FIFO, and then using another signal(S4) tell every other process what to do.
When giving S1 to the process, it sometimes works for 1,2 or 3 processes, when sending S2 to any process, P2 dies, and only P2. I don't know why it works like that.
Yes, i have to use Signals + FIFO.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#define MAX 1000
#define S1 SIGINT
#define S2 SIGUSR1
#define S3 SIGUSR2
#define S4 SIGCONT
#define SIGNAL "\033[1;33m\033[5m>> SIGNAL <<\033[0m\n"
void signal_callback(int signo);
void signal_rcv();
void signal_handling();
int read_line(char text[], int n);
struct msg_buffer {
long msg_type;
char msg_text[100];
} m;
int fd;
char buf[2];
char inter_snd=0, inter_rcv=0, work = 1, quit = 0;
int main()
{
key_t key = ftok(".", 5);
key_t key2 = ftok(",", 4);
int msg_id = msgget(key, 0666 | IPC_CREAT);
int msg_id2 = msgget(key2, 0666 | IPC_CREAT);
mkfifo("/tmp/fifo", 0666);
if(msg_id == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
if(msg_id2 == -1)
{
perror("msgget");
exit(EXIT_FAILURE);
}
if(fork()==0)
{
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_rcv);
do
{
if(read_line(m.msg_text, MAX)!=EOF)
{
if(work)
{
m.msg_type=1;
int length;
length = strlen(m.msg_text);
if(msgsnd(msg_id, &m, sizeof(m),0)==-1)
{
perror("msgsnd");
exit(EXIT_FAILURE);
}
printf("[P1]Sending message.\n");
}
}
}while(1);
exit(0);
}
if(fork()==0)
{
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_rcv);
do
{
if(work)
{
m.msg_type=1;
if(msgrcv(msg_id, &m, sizeof(m), 1, 0)==-1)
{
perror("msgsnd");
exit(1);
}
else printf("[P2]Receiving message.\n");
int length = strlen(m.msg_text), i=0, plus=0, pass=1;
char check[1];
for(;i<length;i++)
{
check[0]=m.msg_text[i];
if((i == 0 && m.msg_text[0]=='+') || (i == length-1 && m.msg_text[length-1] == '+'))
{
printf("Bad\n");
pass=0;
break;
}
if((check[0]<'0' || check[0]>'9') && check[0] != '+')
{
printf("Bad\n");
pass=0;
break;
}
else if(check[0] == '+')
{
if(plus==1)
{
printf("Bad\n");
pass=0;
break;
}
plus++;
}
else plus =0;
}
if(pass==1)
{
m.msg_type=2;
if(msgsnd(msg_id2, &m, sizeof(m),0)==-1)
{
perror("msgsnd");
}
printf("[P2]Sending message.\n");
}
}
}while(1);
exit(0);
}
if(fork()==0)
{
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_rcv);
do
{
if(work)
{
m.msg_type=2;
if(msgrcv(msg_id2, &m, sizeof(m), 2, 0)==-1)
{
perror("msgsnd");
}
printf("[P3]Receiving message.\n");
int count=0, i=0,length = strlen(m.msg_text), nr=0, sum=0;
char check[1];
int numbers[20];
for(; i<length; i++)
{
check[0]= m.msg_text[i];
if(check[0] == '+')
{
char number[20];
strncpy(number, m.msg_text+(i-count), count);
number[count] = '\0';
int a = atoi(number);
numbers[nr] = a;
nr++;
count =0;
}
count++;
}
{
char number[20];
strncpy(number, m.msg_text+(i-count), count);
number[count] = '\0';
int a = atoi(number);
numbers[nr] = a;
nr++;
count =0;
}
i=0;
for(;i<nr; i++)
{
sum += numbers[i];
}
printf("Sum: %d\n", sum);
}
}while(1);
exit(0);
}
wait(NULL);
wait(NULL);
wait(NULL);
printf("Program end.\n");
msgctl(msg_id, IPC_RMID, NULL);
msgctl(msg_id2, IPC_RMID, NULL);
remove("/tmp/fifo");
}
int read_line(char text[], int n)
{
char *ptext;
int return_value;
int length;
ptext = fgets(text, n, stdin);
if(ptext == NULL)
{
return_value = EOF;
}
else
{
length = strlen(text);
if(length>0 && text[length-1]=='\n') text[length-1]='\0';
return_value=1;
}
return return_value;
}
void signal_callback(int signo)
{
//printf("%sSignal %d in PID %d\n", SIGNAL, signo, (int)getpid());
inter_snd = signo;
signal_handling();
}
void signal_rcv()
{
//printf("cos");
fd=open("/tmp/fifo", O_RDWR);
if(read(fd, &inter_snd, sizeof(char)))
{
//printf("przeczytal");
}
//printf("inter_snd = %d\n", inter_snd);
switch (inter_snd)
{
case S1:
//printf("%d Quitting...\n", (int)getpid());
_exit(0);
break;
case S2:
//printf("%d Stopping...\n", (int)getpid());
work = 0;
break;
case S3:
//printf("%d Starting...\n", (int)getpid());
work = 1;
break;
default: break;
//printf("There's garbage in memory :/..\n");
}
}
void signal_handling(void)
{
if (inter_snd>0)
{
//printf("Signal received...\n");
fd = open("/tmp/fifo", O_RDWR);
write(fd, &inter_snd, sizeof(char));
write(fd, &inter_snd, sizeof(char));
write(fd, &inter_snd, sizeof(char));
inter_snd = 0;
//printf("Sending to other processes\n");
kill(0, S4);
}
}
(Used non-async functions just to let me see what is happening)

C, timer_settime() error: invalid argument, after timer_delete()?

I'm doing a simple program where I repeatedly create and destroy some timers; with first timer, program runs correctly, creating and destroying timers; but with second timer, when I do timer_settime(), i get error "Invalid argument"; without timer delete, only disarming timer, code runs correctly; why this?
This is my code:
#include <signal.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
int d,x = 0;
void err_exit(char* str)
{
perror(str);
exit(EXIT_FAILURE);
}
void sighandler(int sig, siginfo_t *si, void *uc)
{
(void) sig;
(void) uc;
d = si->si_value.sival_int;
++x;
}
void handle_signal(struct sigaction* sa)
{
sa->sa_flags = SA_SIGINFO;
sa->sa_sigaction = sighandler;
sigemptyset(&sa->sa_mask);
if (sigaction(SIGRTMAX,sa,NULL) == -1)
err_exit("sigaction");
}
void create_timer(struct sigevent* sev,timer_t* timer_id,int i)
{
union sigval s;
s.sival_int = i+11;
printf("value: %d\n",i);
sev->sigev_notify = SIGEV_SIGNAL;
sev->sigev_signo = SIGRTMAX;
sev->sigev_value = s;
timer_create(CLOCK_REALTIME,sev,timer_id);
}
void set_timer(timer_t timer_id,struct itimerspec* ts,int j)
{
if(ts == NULL)
printf("itimerspec null\n");
printf("creating timer %ju\n",timer_id);
if (timer_settime(timer_id, 0, ts, NULL) == -1){
printf("errno code: %d\n",errno);
err_exit("timer_settime");
}
}
void initialize_timerspec(struct itimerspec* ts)
{
ts->it_value.tv_sec = 2;
ts->it_value.tv_nsec = 5;
ts->it_interval.tv_sec = 0;
ts->it_interval.tv_nsec = 0;
}
void reset_timer(timer_t timer_id,int j)
{
printf("ok1\n");
struct itimerspec its;
memset((void*)&its, 0, sizeof(its));
printf("tv_sec %d tv_nsec %d tv_sec2 %d tv_nsec2 %d\n",its.it_value.tv_sec,its.it_value.tv_nsec,its.it_interval.tv_sec,its.it_interval.tv_nsec);
printf("disarming timer %ju\n",timer_id);
if(timer_settime(timer_id, 0, &its, NULL) == -1)
err_exit("disarming timer\n");
if (timer_delete(timer_id) == -1){
printf("errno code: %d\n",errno);
err_exit("timer_settime");
}
printf("ok2\n");
printf("delete timer\n");
}
void* thread(void* arg)
{
(void) arg;
sleep(10);
printf("awake thread\n");
return NULL;
}
int main()
{
struct sigaction sa;
struct itimerspec ts[10];
struct sigevent sev[10];
timer_t timer_id[10];
int j;
handle_signal(&sa);
for(j = 0; j < 10; j++){
create_timer(&(sev[j]),&(timer_id[j]),j);
initialize_timerspec(&(ts[j]));
set_timer(&(timer_id[j]),&(ts[j]),j);
reset_timer(timer_id[j],j);
}
sleep(10);
printf("d = %d\n",d);
printf("received signal %d times\n",x);
exit(EXIT_SUCCESS);
}

Resources