Building semaphores using Mutexes - c

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.

Related

In my C code i run into some trouble writing text when a signal gets triggered

My code builds a child process and multiple grandchildren (based on N_GRANDKIDDIES).
My problem appears in the handler for the SIGCHLD signal... When I write the pid of the current grandchild and another value, the outcome in the console is very inconsistent... there are often multiple rows missing, for example, like this:
PID:12311
PID:12312
PID:12314
PID:12313
File for Saving Signals
Grandchild with pid:12511 has called SIGUSR1 25139 times
(Missing the other grandchildren here)
Process returned 0 (0x0).....
Hope someone can help me here!
my Code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <sys/resource.h>
#define TESTTIME 3
#define FNAME "testfile.txt"
#define N_GRANDKIDDIES 4
#define SLEEPSEC 0
#define SLEEPNSEC 2
// prototypen
int kiddyscode(void);
int grandkiddyscode();
int nanosleep(const struct timespec *req, struct timespec *rem);
void syserr(char* message);
// global
int pids[N_GRANDKIDDIES];
int counter[N_GRANDKIDDIES];
int n_grandkiddies;
int stop = 0;
void syserr(char* message)
{
int i,j;
j=strlen(message);
printf("Erro ");
for(i=0;i<j;i++)
{
printf("%c",*message++);
}
printf("Error No.: %d\n",errno);
strerror(errno);
exit(0);
}
void initSignalhandler(int sig, struct sigaction sa , void (*handler))
{
memset (&sa, 0,sizeof(sa));
if(sig == SIGCHLD || sig == SIGUSR1) sa.sa_flags = SA_SIGINFO;
sa.sa_handler = handler;
sigaction(sig, &sa, NULL);
if ((int)(uintptr_t)sigaction == -1)
{
syserr("Error SigAction\n");
exit(-1);
}
}
void handle_sigalrm(int sig)
{
stop = 1;
}
void handle_sigusr(int sig, siginfo_t *si, void *data)
{
for (int i=0; i<N_GRANDKIDDIES-1; i++)
{
if ((int)si->si_pid == pids[i]) counter[i]++;
}
}
void handle_sigchld(int sig, siginfo_t *si, void *data)
{
pid_t pid;
int status, i;
FILE *fp;
fp = fopen(FNAME, "a");
// Fehler
if (fp == NULL)
{
syserr("Error\n");
exit(-1);
}
wait(NULL);
n_grandkiddies--;
for (i=0; i<N_GRANDKIDDIES-1;i++)
{
pid = waitpid(-1, &status, WNOHANG);
if (pid > 0)
{
n_grandkiddies--;
fprintf(fp, "Grandchild with pid:%i has callled SIGUSR1 %i times\n", pids[i], counter[i]);
}
}
fclose(fp);
}
int main()
{
FILE *fp;
fp = fopen(FNAME, "w");
if (fp == NULL)
{
syserr("Error\n");
exit(-1);
}
fprintf(fp ,"File for Saving Signals\n");
fclose(fp);
switch(fork())
{
case -1:
syserr("Fork Error\n");
exit(-1);
break;
case 0:
kiddyscode();
return 0;
default:
if(wait(NULL) == -1)
{
syserr("Error");
}
}
fp = fopen(FNAME, "r");
if (fp == NULL)
{
syserr("Error\n");
exit(-1);
}
char c;
while((c = fgetc(fp)) != EOF)
printf("%c", c);
fclose(fp);
return 0;
}
int kiddyscode(void)
{
struct sigaction sa1;
initSignalhandler(SIGCHLD, sa1, handle_sigchld);
initSignalhandler(SIGUSR1, sa1, handle_sigusr);
for(int i = 0; i < N_GRANDKIDDIES; i++)
{
pids[i]= fork();
// Erstellung durch fork
// -1 = Fehler
if(pids[i] == -1)
{
syserr("Fork Error\n");
exit(-1);
}
else if(pids[i]==0)
{
grandkiddyscode();
exit(0);
}
// wird von Kiddy ausgeführt
else
{
n_grandkiddies++;
}
}
int i=0;
while (n_grandkiddies>0){
i++;
pause();
if (errno==EINTR) continue;
if (i>1) break;
continue;
}
return 0;
}
int grandkiddyscode()
{
printf("PID:%i\n", getpid());
// Signalhandler initialisieren
struct sigaction sa1;
initSignalhandler(SIGALRM, sa1, handle_sigalrm);
// Alarm stellen
alarm(TESTTIME);
int ppid = getppid();
struct timespec ts;
ts.tv_sec = SLEEPSEC;
ts.tv_nsec = SLEEPNSEC;
while (stop != 1)
{
kill(ppid, SIGUSR1);
nanosleep(&ts, NULL);
}
return 0;
}

Random core dumps

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.

Producer consumer semaphore value is not correct

I'm trying to implement producer-consumer problem in C using processes and System V IPC and I'm stuck on one thing. This is early version of my code (without implementing queue operations or even producer and consumer executing in loop) that I was using to learn and test how semaphores work:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <time.h>
#include "sem.h"
#include "shm.h"
#define BUFFER_SIZE 9
int full;
int empty;
int mutex;
struct buff {
int queue[BUFFER_SIZE];
} *buffer;
void producer();
void consumer();
int main() {
int parent_pid, pid, i;
parent_pid = getpid();
int shmid = allocate_shared_memory(sizeof(*buffer));
buffer = (struct buff *) attach_shared_memory(shmid);
for (i = 0; i < BUFFER_SIZE; i++) {
buffer->queue[i] = 0;
}
full = sem_allocate();
empty = sem_allocate();
mutex = sem_allocate();
printf("Full %d\n", full);
printf("Empty %d\n", empty);
printf("Mutex %d\n", mutex);
sem_init(full, 0);
sem_init(empty, BUFFER_SIZE);
sem_init(mutex, 1);
printf("Full value %d\n", sem_get_val(full));
printf("Empty value %d\n", sem_get_val(empty));
printf("Mutex value %d\n", sem_get_val(mutex));
srand(time(0));
pid = fork();
if (!pid) {
printf("Producer here: %d\n", getpid());
producer();
printf("Full value after prod() %d\n", sem_get_val(full));
return 0;
} else printf("Created new producent: %d\n", pid);
sleep(1);
pid = fork();
if (!pid) {
printf("Consumer here: %d\n", getpid());
printf("Full value before cons() %d\n", sem_get_val(full)); //here I always get 0
consumer();
return 0;
} else printf("Created new consumer: %d\n", pid);
while (1)
{
int status;
pid_t done = wait(&status);
if (done == -1)
{
if (errno == ECHILD) break; // no more child processes
}
else
{
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
exit(1);
}
}
}
if (getpid() == parent_pid) {
sem_deallocate(full);
sem_deallocate(empty);
sem_deallocate(mutex);
}
}
void producer() {
sem_wait(empty);
sem_wait(mutex);
printf("Producer is producing!\n");
buffer->queue[0]=0;
sem_post(mutex);
sem_post(full);
}
void consumer() {
sem_wait(full);
sem_wait(mutex);
printf("Consumer is consuming!\n");
sem_post(mutex);
sem_post(empty);
}
int sem_allocate() {
return semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
}
void sem_deallocate(int semid) {
if (semctl(semid, 0, IPC_RMID, NULL) == -1)
{
perror("Error releasing semaphore!\n");
exit(EXIT_FAILURE);
}
}
int sem_init(int semid, int value) {
union semun arg;
arg.val = value;
if (semctl(semid, 0, SETVAL, arg) == -1) {
perror("semctl");
return -1;
}else return 1;
}
int sem_wait(int semid) {
printf("Someone is waiting %d\n", semid);
struct sembuf sem = { 0, -1, SEM_UNDO };
return semop(semid, &sem, 1);
}
int sem_post(int semid) {
printf("Someone is posting %d\n", semid);
struct sembuf sem = { 0, 1, SEM_UNDO };
return semop(semid, &sem, 1);
}
int sem_get_val(int semid) {
return semctl(semid, 0, GETVAL, 0);
}
int allocate_shared_memory(int size) {
return shmget(IPC_PRIVATE, size, IPC_CREAT | SHM_W | SHM_R);
}
void deallocate_shared_memory(const void* addr, int shmid) {
shmctl(shmid, IPC_RMID, 0);
}
void* attach_shared_memory(int shmid) {
return shmat(shmid, NULL, 0);
}
sem.h:
#include <sys/types.h>
#include <errno.h>
union semun {
int val;
struct semid_ds *buf;
ushort* array;
};
int sem_post(int);
int sem_wait(int);
int sem_allocate();
void sem_deallocate(int);
int sem_init(int, int);
int sem_get_val(int);
shm.h:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int allocate_shared_memory(int size);
void deallocate_shared_memory(const void* addr, int shmid);
void* attach_shared_memory(int shmid);
Why before executing consumer function value of full semaphore is 0? Even if right after producer finishes his job the value is 1...
I'm new to this kind of topics so maybe there is an obvious explenation of the situation, but I have no idea what can I do and hope you can help me.
You initialize the "full" semaphore to zero. Your "child" producer, prior to exiting calls your sem_post() function, which calls semop() with a SEM_UNDO argument.
int sem_post(int semid) {
printf("Someone is posting %d\n", semid);
struct sembuf sem = { 0, 1, SEM_UNDO };
return semop(semid, &sem, 1);
}
The Ubuntu Linux man page for semop says the following about SEM_UNDO:
... If an operation specifies SEM_UNDO, it will be automatically
undone when the process terminates.
This means, "producer" increments "full" prior to exiting, then after it exits the system "undoes" the increment (i.e. it decrements "full") setting it back to zero.
So,for the purposes of the "full" semaphore, you should NOT specify SEM_UNDO.

Use semaphores to synchronize shared memory

I have the following code which works fine with the sleep time. But I want to remove sleep and use semaphores to synchronize the threads ( so that the reader waits till data is available in shmptr.) How do I do that? What do I use:
sem_t mutex or
pthread_mutex_t mutex?
P.S : I tried using both above options separately (not shown in above code though) but didn't get desired result.Most of the times I was getting error in shmget in reader - "shmget in reader: No such file or directory".
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <semaphore.h>
#include <errno.h>
void *write(void *t)
{ char str[100] = "\0";
char str1[50];
key_t key;
char *shmptr;
int shmid;
if( (key = ftok("shmSemphore.c",'B')) == -1)
{
perror("ftok in writer");
pthread_exit(NULL);
}
if( (shmid = shmget(key, 1024, 0666 | IPC_CREAT)) == -1)
{
perror("shmget in writer");
pthread_exit(NULL);
}
shmptr = shmat(shmid,0,0);
if( (shmptr == (char *)(-1)))
{
perror("shmget in writer");
pthread_exit(NULL);
}
printf("ENter your text :- ");
//scanf("%s",str);
fgets(str,sizeof(str),stdin);
strcpy(shmptr,str);
sleep(2);
shmdt(shmptr);
if( shmctl(shmid, IPC_RMID, NULL) == -1 )
{
perror("shmctl");
exit(-1);
}
pthread_exit(NULL);
}
void *read(void *t)
{ sleep(2);
key_t key;
char *shmptr;
int shmid;
if( (key = ftok("shmSemphore.c",'B')) == -1)
{
perror("ftok in writer");
pthread_exit(NULL);
}
if( (shmid = shmget(key, 1024, 0)) == -1)
{
perror("shmget in reader");
pthread_exit(NULL);
}
shmptr = shmat(shmid,0,0);
if( (shmptr == (char *)-1))
{
perror("shmget in writer");
pthread_exit(NULL);
}
printf("your text:- %s \n",shmptr);
pthread_exit(NULL);
}
int main()
{
pthread_t reader,writer;
int rt;
long t = 0;
rt = pthread_create(&writer,NULL,write,(void *)t);
/*if(rt == -1)
{ perror("writer thread");
pthread_exit(NULL);
}*/
rt = pthread_create(&reader,NULL,read,(void *)t);
/*if(rt == -1)
{ perror("writer thread");
pthread_exit(NULL);
}*/
pthread_join(writer,NULL);
pthread_join(reader,NULL);
return 0;
}

C language: Children don't exit, nor terminate and are not killed my parent process too

I can't exit or terminate children processes sending a signal.
Could you please tell me what I'm doing wrong in this code:
//###################################### INVERTER.C (main)
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#include <unistd.h>
#include "timeprofiler.h"
#include "ppmtools.h"
//Global vars:
int shmids[4], shmPixelId, *total_lines, *processed_lines, *next_line, *buf_vars;
//To share unnamed semaphores between processes, they must be allocated in a shared memory.
mem_struct *sh_mm;
//unnamed semaphores
sem_t *mutex1, *mutex2, *mutex3, *sem_remaining_lines;
//struct that will hold the image in shared memory
image_struct *image;
pid_t *workersPID;
header *h;
int main(int argc, char *argv[]) {
int i, j, k, cur = 0, id;
pixel *row;
double start, stop, startms, stopms;
if (argc < 3) {
printf("Incorrect usage.\nPlease use \"./invert input_filename.ppm output_filename.ppm\"\n");
return -1;
}
//BLOCK ALL SIGNAL
sigset_t block_ctrlc;
sigfillset(&block_ctrlc);
sigdelset(&block_ctrlc, SIGINT);
sigprocmask(SIG_BLOCK, &block_ctrlc, NULL);
//start timer
start = getCurrentTimeMicro();
startms = getCurrentTimeMili();
printf("Opening input file [%s]\n", argv[1]);
FILE *fpin = fopen(argv[1], "r");
if (fpin == NULL) {
printf("Could not open input file\n");
return -1;
}
printf("Opening output file [%s]\n", argv[2]);
FILE *fpout = fopen(argv[2], "w");
if (fpout == NULL) {
printf("Could not open output file\n");
return -1;
}
printf("Getting header\n");
h = getImageHeader(fpin);
if (h == NULL) {
printf("Error getting header from file\n");
return -1;
}
printf("Got file Header: %s - %u x %u - %u\n", h->type, h->width, h->height, h->depth);
printf("Saving header to output file\n");
if (writeImageHeader(h, fpout) == -1) {
printf("Could not write to output file\n");
return -1;
}
init();
printf("After init...\n");
//alloc mem space for one row (width * size of one pixel struct)
row = (pixel *) malloc(h->width * sizeof (pixel));
printf("Starting work\n");
for (i = 0; i < h->height; i++) {
printf("Reading row... \n");
if (getImageRow(h->width, row, fpin) == -1) {
printf("Error while reading row\n");
}
printf("Got row %d || \n", (i + 1));
for (j = cur, k = 0; j < cur + h->width; j++, k++) {
image->pixel_data[j].red = row[k].red;
image->pixel_data[j].blue = row[k].blue;
image->pixel_data[j].green = row[k].green;
}
cur += h->width;
}
/*Creates workers*/
workersPID = (pid_t*) malloc(sizeof (pid_t) *((NUM_WORKERS)));
for (i = 0; i < NUM_WORKERS; i++) {
id = fork();
if (id == -1) {
printf("Error creating worker no %d\n", i);
return (EXIT_FAILURE);
} else if (id == 0) {
workersPID[i] = getpid();
printf("Launching son with pid %d\n", getpid());
worker(i);
}
}
cur = 0;
sem_wait(mutex2);
/*Writes the invert image on the output file*/
for (i = 0; i < h->height; i++) {
for (j = cur, k = 0; j < cur + h->width; j++, k++) {
row[k].red = image->pixel_data[j].red;
row[k].blue = image->pixel_data[j].blue;
row[k].green = image->pixel_data[j].green;
}
cur += h->width;
printf("Saving row... \n");
if (writeRow(h->width, row, fpout) == -1) {
printf("Error while writing row\n");
}
printf("Done\n");
}
printf("Cleaning up...\n");
//clean up row
free(row);
//clean up header
free(h);
printf("Closing file pointers.\n");
fclose(fpin);
fclose(fpout);
//stop timer
stop = getCurrentTimeMicro();
stopms = getCurrentTimeMili();
for (i = 0; i < NUM_WORKERS; i++) {
if (workersPID[i]) {
kill(workersPID[i], SIGTERM);
waitpid(workersPID[i], NULL, 0);
}
}
terminate();
printTimeElapsed(start, stop, "microseconds");
printTimeElapsed(startms, stopms, "miliseconds");
printf("Done!\n");
return 0;
}
void init() {
//create shared memory to hold the source image:
if ((shmids[0] = shmget(IPC_PRIVATE, sizeof (image_struct), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate image struct failed. Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
image = (image_struct*) shmat(shmids[0], NULL, 0);
//shared memory to allocate the pointer to pointer pixel_data
if ((shmids[1] = shmget(IPC_PRIVATE, h->width * h->height * sizeof (pixel), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate pixel_data array failed. Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
image->pixel_data = (pixel*) shmat(shmids[1], NULL, 0);
/*Shared Memory segment for 3 integers*/
if ((shmids[2] = shmget(IPC_PRIVATE, 3 * sizeof (int), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate the 3 integers failed. Errno returned; %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
buf_vars = (int*) shmat(shmids[2], NULL, 0);
total_lines = &buf_vars[0];
processed_lines = &buf_vars[1];
next_line = &buf_vars[2];
*processed_lines = *next_line = 0;
*total_lines = h->height;
if ((shmids[3] = shmget(IPC_PRIVATE, sizeof (mem_struct), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate mem_Struct for semaphores failed. Errno returned %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sh_mm = (mem_struct*) shmat(shmids[3], NULL, 0);
if (sem_init(&sh_mm->mutex1, 1, 1) == -1) {
printf("Error initializing semaphore mutex1.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex1 = &sh_mm->mutex1;
if (sem_init(&sh_mm->mutex2, 1, 0) == -1) {
printf("Error initializing semaphore mutex2.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex2 = &sh_mm->mutex2;
if (sem_init(&sh_mm->mutex3, 1, 1) == -1) {
printf("Error initializing semaphore mutex3.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex3 = &sh_mm->mutex3;
if (sem_init(&sh_mm->sem_remaining_lines, 1, h->height) == -1) {
printf("Error initializing semaphore sem_remaining_lines.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sem_remaining_lines = &sh_mm->sem_remaining_lines;
}
/*Worker process*/
void worker(int id) {
int i, k, cur = 0;
pixel *row;
//Block all signals, except SIGINT and SIGKILL which are handled
sigset_t block_ctrlc;
sigfillset(&block_ctrlc);
sigdelset(&block_ctrlc, SIGINT);
sigdelset(&block_ctrlc, SIGTERM);
sigprocmask(SIG_BLOCK, &block_ctrlc, NULL);
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
while (sem_wait(sem_remaining_lines)!= -1) { //if there are still lines to read, go on
sem_wait(mutex3);
cur = *next_line; //current image's line
*next_line += h->width; //refreshs line for the next worker
sem_post(mutex3);
row = (pixel *) malloc(h->width * sizeof (pixel));
for (i = cur, k = 0; i < cur + h->width; i++, k++) {
row[k].red = image->pixel_data[i].red;
row[k].blue = image->pixel_data[i].blue;
row[k].green = image->pixel_data[i].green;
}
//printf("% - Inverting row... \n",id);
invertRow(h->width, row); //invert
//printf("Done || \n");
for (i = cur, k = 0; i < cur + h->width; i++, k++) {
image->pixel_data[i].red = row[k].red;
image->pixel_data[i].blue = row[k].blue;
image->pixel_data[i].green = row[k].green;
}
sem_wait(mutex1);
*processed_lines += 1; //increases the number of inverted lines
if (*processed_lines == *total_lines) { //check if it reaches last line
sem_post(mutex2); //if so, wakes the master telling that is ready
}
sem_post(mutex1);
}
//printf("Son %d is exiting\n",id);
exit(0);
}
void handle_signal(int signum) {
if(signum == SIGINT)
signal(SIGINT, handle_signal);
else
signal(SIGTERM, handle_signal);
exit(0);
}
void terminate() {
int i;
//close semaphores
sem_destroy(mutex1);
sem_destroy(mutex2);
sem_destroy(mutex3);
sem_destroy(sem_remaining_lines);
//cleans up shared memory = removes shared memory segments
for (i = 0; i < 4; i++) {
shmctl(shmids[i], IPC_RMID, NULL);
}
}
I'm gonna leave the explanation of the assignment (that has already finished btw)here:
1 page pdf
Your worker threads have SIGTERM blocked (because it was blocked in main, and sigprocmask doesn't remove signals from the blocked set unless explicitly told to do so)
You may want to do something like this in the worker instead:
sigemptyset(&block_ctrlc);
sigaddset(&block_ctrlc, SIGINT);
sigaddset(&block_ctrlc, SIGTERM);
sigprocmask(SIG_UNBLOCK, &block_ctrlc, NULL);
Alternately, call sigprocmask with SIG_SETMASK.

Resources