Reputation: 4146
I am trying to understand IPC mechanisms in unix-like systems. After compilation I can't run my program since it crashes before anything gets executed (can't even print first line in main()) and get segfault.
Just in case you wanted to know what happens here: dispatcher is a program that stores messages produced by factory and assigns them to client processes on their demand.
I am on Mint 18 wih 4.4 generic kernel.
dispatcher.c
code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include "booth.h"
typedef struct message_queue{
pid_t *clients_served;
message msg;
struct message_queue *next;
} message_queue;
int stop = 0;
static message *msg = NULL;
message_queue message_vector[INT_MAX];
unsigned int number_of_clients = 0;
static pid_t *clients_list = NULL;
message_queue* new_queue_element(){
int i;
message_queue *new_element = malloc(sizeof(message_queue));
memcpy(&new_element->msg, msg, sizeof(message_queue));
new_element->clients_served = malloc(number_of_clients*sizeof(number_of_clients));
// new_element->msg = *msg;
new_element->next = NULL;
for(i = 0; i < number_of_clients; i++){
new_element->clients_served[i] = 0;
}
return new_element;
}
void append_queue(){
int index;
printf("Appending with message with id: %d\n", msg->id);
message_queue *new_element = new_queue_element();
index = new_element->msg.type;
if(&message_vector[index] == NULL){
message_vector[index] = *new_element;
}
else {
message_queue *mq = &message_vector[index];
while(mq->next != NULL){
mq = mq->next;
}
mq->next = new_element;
}
}
void show_queue(){
int i = 0;
message_queue *mq;
for(i = 0; i < INT_MAX; i++){
printf("message type: %d\n", i);
mq = &message_vector[i];
while(mq != NULL){
printf("ID: %d, contents: %s\n", mq->msg.id, mq->msg.contents);
mq = mq->next;
}
}
}
void read_clients_pids(){
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
int i = 0;
fp = fopen("clients.txt", "r");
if (fp == NULL)
exit(1);
// get number of clients
while ((read = getline(&line, &len, fp)) != -1) {
number_of_clients++;
}
fclose(fp);
clients_list = (int*)malloc(number_of_clients * sizeof(unsigned int));
fp = fopen("clients.txt", "r");
if (fp == NULL)
exit(1);
// fill clients_list with clients PIDs
i = 0;
while ((read = getline(&line, &len, fp)) != -1) {
clients_list[i++] = (pid_t) atoi(line);
}
fclose(fp);
printf("Dispatcher will work with following clients:\n");
for(i = 0; i < number_of_clients; i++)
printf("%d\n", clients_list[i]);
if (line)
free(line);
}
void prepare_factory_shm(message **msg, key_t *key, int *shmid){
get_factory_key(key);
get_shmid(shmid, *key);
attach(msg, *shmid);
}
void give_message_to_client(pid_t client){
printf("Sending message to: %d\n", (int)client);
}
void signal_request_handler(int sig, siginfo_t *siginfo, void *context){
/*
SIGUSR1 is used for handling communication with factory
SIGUSR2 is used for handling communication with clients.
if number_of_clients equals to 0, we read new clients list.
otherwise we give newest message still not read by client. If all messages have been read NULL is set
SIGTERM sets stop variable to 1 break loop in main() and clean up mess.
*/
if(sig == SIGUSR1){
printf("SIGUSR1 received by: %d sent by: %d\n", getpid(), siginfo->si_pid);
append_queue();
}
else if(sig == SIGUSR2){
printf("SIGUSR2 received by process: %d\n", getpid());
if(number_of_clients == 0){
read_clients_pids();
}
else{
give_message_to_client(siginfo->si_pid);
}
}
else if(sig == SIGTERM){
printf("SIGTERM received by: %d\n", getpid());
stop = 1;
}
}
void prepare_sigaction(){
static struct sigaction factory_action;
static struct sigaction client_action;
static struct sigaction terminate_action;
factory_action.sa_sigaction = *signal_request_handler;
factory_action.sa_flags |= SA_SIGINFO;
sigemptyset(&factory_action.sa_mask);
sigaction(SIGUSR1, &factory_action, NULL);
client_action.sa_sigaction = *signal_request_handler;
client_action.sa_flags |= SA_SIGINFO;
sigemptyset(&client_action.sa_mask);
sigaction(SIGUSR2, &client_action, NULL);
terminate_action.sa_sigaction = *signal_request_handler;
terminate_action.sa_flags |= SA_SIGINFO;
sigemptyset(&terminate_action.sa_mask);
sigaction(SIGTERM, &terminate_action, NULL);
}
int main(int argc, char *argv[]){
key_t key;
int shmid;
read_clients_pids();
prepare_factory_shm(&msg, &key, &shmid);
prepare_sigaction();
// wait for termination signal
while(!stop)
;
// clean up
show_queue();
shmdt(msg);
shmctl(shmid, IPC_RMID, NULL);
exit(0);
}
booth.h
code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <signal.h>
#include<string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <fcntl.h>
#define BUFSIZE 1024
#define PERM 0644
typedef struct message{
int id;
int type;
char contents[BUFSIZE];
unsigned long len;
} message;
char *get_client_com_file_name(pid_t pid);
void prepare_client_com(pid_t pid);
void prepare_factory_com();
void inform_dispatcher(int dispatcher_id);
message message_request();
void get_client_key(key_t *key, pid_t client_pid);
void get_factory_key(key_t *key);
void get_shmid(int *shmid, const key_t key);
void create_shmid(int *shmid, const key_t key);
void attach(message **msg, const int shmid);
And booth.c
code:
#include "booth.h"
static char pid_char[128];
char * get_client_com_file_name(pid_t pid){
memset(pid_char, 0, 127);
sprintf(pid_char,"%d", pid);
printf("pid_char: %s\n", pid_char);
strcat(pid_char, "_com");
return pid_char;
}
void inform_dispatcher(int dispatcher_id){
printf("Informing: %d\n", dispatcher_id);
kill(dispatcher_id, SIGUSR1);
}
static void get_key(key_t *key, char* file_name){
if((*key = ftok(file_name, 'R')) == -1){
int err = errno;
perror("ftok");
printf("Error number: %d\n", err);
exit(1);
}
}
void get_factory_key(key_t *key){
get_key(key, "factory_com");
}
void get_client_key(key_t *key, pid_t client_pid){
char buf[10];
sprintf(buf, "%d", client_pid);
get_key(key, buf);
}
void create_shmid(int *shmid, const key_t key){
if((*shmid = shmget(key,BUFSIZE, PERM | IPC_CREAT)) == -1){
int err = errno;
perror("shmget");
printf("Error number: %d\n", err);
exit(1);
}
}
void get_shmid(int *shmid, const key_t key){
if((*shmid = shmget(key,BUFSIZE, PERM)) == -1){
int err = errno;
perror("shmget");
printf("Error number: %d\n", err);
exit(1);
}
}
void attach(message **msg, const int shmid){
*msg = (message*) shmat(shmid, (void *)0, 0);
if (msg == (message**)(-1)){
perror("shmat");
exit(1);
}
}
message message_request(pid_t pid){
kill(SIGUSR2, pid);
message m;
return m;
}
Upvotes: 1
Views: 240
Reputation: 852
I run sizeof(messeage_queue) and I got 1056 bytes nearly 1 KB.
In line 22, you allocated INT_MAX * 1056 bytes = 2 TB !!.
message_vector is a global variable, the memory is allocated in the BSS before running the program, that's why you see a segmentation fault before your code even runs.
Upvotes: 1