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

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);
}

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;
}

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.

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.

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.

Resources