Shared semaphore in c in linux - c

Here is part of character function which sends data in range 256 to 1024 bytes to buffer
semaphore_p(semMutexAll);//critical section
int charByte =rand() % 768 + 256;
for(i=0 ; i<charByte ; i++)
semaphore_p(semBuff);//contor buffer overflow
semaphore_v(semMutexAll);
Here is part of function cpu whic reads 2 bytes from buffer in 10 miliseconds
while(1)
{
semaphore_v(semBuff);
semaphore_v(semBuff);
usleep(10000);
}
Here is semaphores
semBuff = semget((key_t)1234,1,0666|IPC_CREAT); //Gets shared memory Id --> 1234 key
semChar = semget((key_t)1235,1,0666|IPC_CREAT);
semImage = semget((key_t)1236,1,0666|IPC_CREAT);
semAudio = semget((key_t)1237,1,0666|IPC_CREAT);
semVideo = semget((key_t)1238,1,0666|IPC_CREAT);
semMutexCpu = semget((key_t)1239,1,0666|IPC_CREAT);
semMutexAll = semget((key_t)1230,1,0666|IPC_CREAT);
set_semvalue(semBuff,BUFFSIZE);
set_semvalue(semChar,MAXCHR);
set_semvalue(semImage,MAXIMAGE);
set_semvalue(semAudio,MAXAUDIO);
set_semvalue(semVideo,MAXVIDEO);
set_semvalue(semMutexCpu,1);
set_semvalue(semMutexAll,1);
Here is shared memory
key_t ShmKEY;
key_t ShmQ;
int ShmContID;
int ShmQID;
int status;
queue *buffArea;
buffArea = (queue*)malloc(sizeof(queue));
initQueue(buffArea);
control * params;
params = (control*)malloc(sizeof(control));
ShmKEY = ftok("./", 'A');
ShmQ = ftok("./", 'B');
if((ShmContID = shmget(ShmKEY,sizeof(params),IPC_CREAT | 0666)) == -1)
{
//Gets shared memory Id --> IPC_PRIVATE key
perror("shmget");
exit(1);
}
if((ShmQID = shmget(ShmQ,sizeof(buffArea),IPC_CREAT | 0666)) == -1)
{
//Gets shared memory Id --> IPC_PRIVATE key
perror("shmget");
exit(1);
}
Here is semaphore header
#ifndef SHAREDSMPH_H_
#define SHAREDSMPH_H_
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
static int semBuff;
static int semChar;
static int semImage;
static int semAudio;
static int semVideo;
static int semMutexCpu;
static int semMutexAll;
static int set_semvalue(int sem_id,int val)
{
union semun sem_union;
sem_union.val=val;
if(semctl(sem_id,0,SETVAL,sem_union) == -1)
{
fprintf(stderr, "Failed to semvalue\n");
return(0);
}
return (1);
}
static void del_semvalue(int sem_id)
{
union semun sem_union;
if(semctl(sem_id,0,IPC_RMID,sem_union) == -1)
fprintf(stderr, "Failed to delete semaphore\n");
}
static int get_semvalue(int sem_id)
{
union semun sem_union;
int value = semctl(sem_id,0,GETVAL,sem_union);
//printf("semvalue:%d\n",value);
return value;
}
static int semaphore_p(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num=0;
sem_b.sem_op=-1; /* P */
sem_b.sem_flg=SEM_UNDO;
if(semop(sem_id,&sem_b,1) == -1)
{
printf("semaphore_p failed\n");
return (0);
}
return (1);
}
static int semaphore_v(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num=0;
sem_b.sem_op=1; /* V */
sem_b.sem_flg=SEM_UNDO;
if(semop(sem_id,&sem_b,1) == -1)
{
printf("semaphore_v failed\n");
return (0);
}
return (1);
}
#endif
Something wrong in this code? especially semaphores , problem is semaphore values are always initialized in different processes.. When i call semaphore_v and semaphore_p functions in processes they works accurate but for example semBuff semaphore is always initialized to 1024 always.

Related

How to identify whether the access is read or write in Sigaction?

I am using Sigaction for signal handling, and I was trying to differentiate between Read and Write access in case of "SIGSEGV Segmentation Fault". Check the below code for more reference.
#include <signal.h>
#include <ucontext.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void handler(int sig, siginfo_t* info, void* ucontext)
{
int access_type = -1;
ucontext_t* uc = (ucontext_t *)ucontext;
if(uc->uc_mcontext.gregs[REG_ERR] & 0x2)
{
access_type = 2;
}
else
{
access_type = 4;
}
if(access_type == 2)
{
mprotect(info->si_addr, sizeof(int), PROT_READ | PROT_WRITE);
}
else if(access_type == 4)
{
mprotect(info->si_addr, sizeof(int), PROT_READ);
}
}
int main()
{
void *vm_ptr;
int PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
int vm_size = 16 * PAGE_SIZE;
if (posix_memalign(&vm_ptr, PAGE_SIZE, vm_size))
{
fprintf(stderr, "posix_memalign failed\n");
return -1;
}
if (mprotect(vm_ptr, vm_size, PROT_NONE))
{
fprintf(stderr, "mprotect failed\n");
return -1;
}
struct sigaction sa;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handler;
sigaction(SIGSEGV, &sa, NULL);
// Accessing protected memory to generate SIGSEGV
int *ptr = (int *)vm_ptr;
*ptr = 10;
printf("%d\n", *ptr);
return 0;
}
The problem I am facing is it always populates the access_type variable with 4, even if the original access made is "write" access. Am I missing something here? Or is there any other way to identify write access to a memory block?

Message queues: Bad file descriptor in notification

I've created a table of mq file descriptors and I'm trying to pass numbers from stdin by one of them.
I'm using notification using threads and when a number occures in one of the queues it should print for example "Number: 1 from queue: 3".
Here's my code:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <mqueue.h>
#define MAX_LENGTH 20
#define ERR(source) (\
fprintf(stderr, "%s:%d\n", __FILE__, __LINE__),\
perror(source),\
kill(0, SIGKILL),\
exit(EXIT_FAILURE)\
)
static void not_func(union sigval sv) {
mqd_t queue;
uint8_t number;
unsigned msg_prio;
queue = *((mqd_t*)sv.sival_ptr);
static struct sigevent not;
not.sigev_notify = SIGEV_THREAD;
not.sigev_notify_function = not_func;
not.sigev_value.sival_ptr = &queue;
if(mq_notify(queue, &not)<0) ERR("mq_notify");
for(;;) {
if(mq_receive(queue, (char*)&number, 1, &msg_prio)<1) {
if(errno == EAGAIN) break;
else ERR("mq_receive");
printf("Number: %d from queue: %d", number, msg_prio);
}
}
}
void get_queue_name(int nr, char *str) {
snprintf(str, MAX_LENGTH, "/queue%d", nr);
}
mqd_t create_message_queue(int nr) {
mqd_t queue;
char name[MAX_LENGTH] = "";
get_queue_name(nr, name);
struct mq_attr attr;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 1;
if((queue = TEMP_FAILURE_RETRY(mq_open(name, O_RDWR|O_NONBLOCK|O_CREAT, 0600, &attr))) == (mqd_t)-1) ERR("mq open in");
static struct sigevent not;
not.sigev_notify = SIGEV_THREAD;
not.sigev_notify_function = not_func;
not.sigev_value.sival_ptr = &queue;
if(mq_notify(queue, &not)<0) ERR("mq_notify");
return queue;
}
void delete_message_queue(mqd_t queue, int nr) {
char name[MAX_LENGTH] = "";
get_queue_name(nr, name);
mq_close(queue);
if(mq_unlink(name)) ERR("mq_unlink");
}
void usage(void) {
fprintf(stderr, "USAGE: mqueue n\n");
fprintf(stderr, "100 > n > 0 - number of children\n");
exit(EXIT_FAILURE);
}
int main(int argc, char **argv) {
int n, i;
char strnumber[MAX_LENGTH];
int number;
mqd_t *queues;
srand(time(NULL));
if(argc != 2) usage();
n = atoi(argv[1]);
if(n<=0 || n>=100) usage();
queues = (mqd_t*)malloc(sizeof(mqd_t) * n);
if(queues == NULL) ERR("malloc");
for(i = 0; i < n; i++) {
queues[i] = create_message_queue(i+1);
}
while(fgets(strnumber, MAX_LENGTH, stdin)!=NULL) {
number = (uint8_t)atoi(strnumber);
if(number<=0) continue;
int randomQueue = rand()%n;
if(TEMP_FAILURE_RETRY(mq_send(queues[randomQueue], (const char *)&number, 1, (unsigned)randomQueue))) ERR("mq_send");
}
for(i = 0; i < n; i++) {
delete_message_queue(queues[i], i+1);
}
free(queues);
return EXIT_SUCCESS;
}
When I execute my code nothing happens:
or I have such an error:
You pass a pointer to queue (which is a local variable) to the thread (via not.sigev_value.sival_ptr) which runs after that variable goes out of scope. So it gets a dangling pointer.
Either pass the descriptor by value (if it fits in sigval; it should), or store it on the heap (with new/malloc) and pass that pointer.

How to fix " assignment makes pointer from integer without a cast [-Wint-conversion]"? C unix program

I'm writing this 2 programs but I recive this warning: " assignment makes pointer from integer without a cast [-Wint-conversion]".
I'm trying to compile these programs to other Machines, but I recive same problem.
What can I do?
//PROGRAM 1 (PRODUCTOR)
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#define SHMEMSIZE 4096
int main()
{
key_t key_mem=6868;
key_t key_sem=3232;
int id_mem;
int id_sem;
void *addr_mem;
struct sembuf param[1];
if(id_mem = shmget(key_mem,SHMEMSIZE,0) == -1)
{
printf("Errore1\n");
return -1;
}
if(addr_mem =shmat(id_mem,NULL,0) == (void *)-1)
{
printf("Errore2\n");
return -1;
}
if(id_sem = semget(key_sem,2,0)== -1)
{
perror("Errore3\n");
shmdt(addr_mem);
return -1;
}
while(1)
{
param[0].sem_num=1;
param[0].sem_op=-1;
param[0].sem_flg=0;
if(semop(id_sem,param,1)==-1)
{
printf("Errore6\n");
return -1;
}
printf("Scrivi messaggio: ");
if(scanf("%[^\n]", (char *)addr_mem) == 0)
*((char *)addr_mem) = '\0';
getc(stdin);
param[0].sem_num=0;
param[0].sem_op=1;
param[0].sem_flg=0;
if(semop(id_sem,param,1)==-1)
{
printf("Errore7\n");
return -1;
}
}
shmdt(addr_mem);
}
_____________________________________________________
//PROGRAM 2 (CONSUMER)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#define SHMEMSIZE 4096
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int main()
{
key_t key_mem=6868;
key_t key_sem=3232;
int id_mem;
int id_sem;
void *addr_mem;
union semun arg;
struct sembuf param[1];
if(id_mem = shmget(key_mem,SHMEMSIZE,IPC_CREAT|0666) == -1)
{
printf("Errore1");
return -1;
}
if(addr_mem =shmat(id_mem,NULL,0) == (void *)-1)
{
printf("Errore2");
shmctl(id_mem, IPC_RMID, NULL);
return -1;
}
if(id_sem = semget(key_sem,2,IPC_CREAT|0666)== -1)
{
printf("Errore3");
shmctl(id_mem, IPC_RMID, NULL);
shmdt(addr_mem);
return -1;
}
arg.val=0;
if(semctl(id_sem,0,SETVAL,arg)==-1)
{
printf("Errore4");
semctl(id_sem, -1, IPC_RMID,arg);
shmctl(id_sem, IPC_RMID, NULL);
shmdt(addr_mem);
return -1;
}
arg.val=1;
if(semctl(id_sem,1,SETVAL,arg)==-1)
{
printf("Errore5");
semctl(id_sem, -1, IPC_RMID, arg);
shmctl(id_sem, IPC_RMID, NULL);
shmdt(addr_mem);
return -1;
}
while(1)
{
param[0].sem_num=0;
param[0].sem_op=-1;
param[0].sem_flg=0;
if(semop(id_sem,param,1)==-1)
{
printf("Errore6");
return -1;
}
printf("Il messaggio scritto è: %s\n",(char *)addr_mem);
param[0].sem_num=1;
param[0].sem_op=1;
param[0].sem_flg=0;
if(semop(id_sem,param,1)==-1)
{
printf("Errore7");
return -1;
}
}
}
My program should simply allow a producer process to write on shared memory and the consumer process to read shared memory.
I first receive this "warning" and after that if I try to run the producer I get a "Segmentation Fault". I absolutely can't understand what's going on.
I suppose that the shared memory is not really created, in fact if I delete the line * ((char *) addr_mem) = '0'; I do not get the "Segmentation Fault", and it is clear that the "Scanf" is not writing anything.
IMO if(id_mem = shmget(key_mem,SHMEMSIZE,IPC_CREAT|0666) == -1) is very bad style, exactly for the problem you have. You forgot to add parantheses around the assignment. You compare the result of shmget with -1 and assign this result to id_mem.
Change it to if((id_mem = shmget(key_mem,SHMEMSIZE,IPC_CREAT|0666)) == -1) or even better
id_mem = shmget(key_mem,SHMEMSIZE,IPC_CREAT|0666);
if (id_mem == -1)
The next ifs have the same problem.

How to create a file Lock with timeout under linux

I'm trying to lock some critical resources that are accessed by multiple applications under linux.
All the applications will call the acquireLock function on the same file when entering the critical section, and the releaseLock when leaving.
If the lock is not acquired for more than timeot the caller will go ahead doing something else.
The code below works whit slow processes, but under stress the lock is easily broken the lock is acquired by multiple processes, so I guess I'm stumbling in a race condition somewhere.
Can somebody point me out why it's not working and what would be the correct implementation?
Thanks a lot!
MV
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
//************************************************************
#define CYCLETIME 1000
//************************************************************
//************************************************************
int acquireLock(char *lockFile, int msTimeout)
{
int lockFd;
int cntTimeout = 0;
if ((lockFd = open(lockFile, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
return -1;
while (flock(lockFd, LOCK_EX | LOCK_NB) < 0){
usleep(CYCLETIME);
cntTimeout++;
if(cntTimeout >= msTimeout){
return -1;
}
}
return lockFd;
}
//*************************************************************
void releaseLock (int lockFd)
{
flock(lockFd, LOCK_UN);
close(lockFd);
}
//************************************************************
It appears that the mistake was in another part of the code, the lock is working as expected.
I share the code I'm using in case it can be helpful to somebody else.
Those are the locking functions:
/* ----------------------------------------------------------------------- *
* Code derived by the flock.c in the "util-linux" ubuntu package
* by Peter Anvin
* ----------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
#include <sys/time.h>
#include <signal.h>
//************************************************************
static sig_atomic_t timeout_expired = 0;
//************************************************************
static void timeout_handler(int sig)
{
(void)sig;
timeout_expired = 1;
}
//************************************************************
int acquireLock(char *lockFile, int msTimeout)
{
struct itimerval timeout, old_timer;
struct sigaction sa, old_sa;
int err;
int sTimeout = msTimeout/1000;
memset(&timeout, 0, sizeof timeout);
timeout.it_value.tv_sec = sTimeout;
timeout.it_value.tv_usec = ((msTimeout-(sTimeout*1000))*1000);
memset(&sa, 0, sizeof sa);
sa.sa_handler = timeout_handler;
sa.sa_flags = SA_RESETHAND;
sigaction(SIGALRM, &sa, &old_sa);
setitimer(ITIMER_REAL, &timeout, &old_timer);
int lockFd;
int cntTimeout = 0;
if ((lockFd = open(lockFile, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
return -1;
while (flock(lockFd, LOCK_EX))
{
switch( (err = errno) ) {
case EINTR: /* Signal received */
if ( timeout_expired )
setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */
return -1; /* -w option set and failed to lock */
continue; /* otherwise try again */
default: /* Other errors */
return -1;
}
}
setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */
return lockFd;
}
//***************************************************************
void releaseLock (int lockFd)
{
flock(lockFd, LOCK_UN);
close(lockFd);
}
//************************************************************
... and those can be tried by reading and writing a FIFO
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "lock.h"
#define LOCKED 1
void main(int argc, char **argv)
{
const char *filename;
const char *fifo_name;
const char *message;
int lockfd, fifoHandle;
filename = argv[1];
fifo_name = argv[2];
message = argv[3];
char bufin[1024];
char bufout[1024];
struct stat st;
int bufsize = strlen(message)+1;
int sleeptime = 0;
int j = 0;
if (stat(fifo_name, &st) != 0)
mkfifo(fifo_name, 0666);
while (1){
if (LOCKED)
lockfd=acquireLock(filename, 15000);
if (lockfd==-1)
printf("timeout expired \n");
fifoHandle= open(fifo_name, O_RDWR);
strcpy(bufin, message);
bufin[bufsize-1] = 0x0;
write(fifoHandle, bufin, sizeof(char)*bufsize);
sleeptime = rand() % 100000;
usleep(sleeptime);
read(fifoHandle, &bufout, sizeof(char)*(bufsize+1));
printf("%s - %d \n", bufout, j);
j= j+1;
if (LOCKED)
releaseLock(lockfd);
sleeptime = rand() % 10000;
}
unlink(fifo_name);
return;
}
by sending in two terminals
./locktestFIFO ./lck ./fifo messageA
./locktestFIFO ./lck ./fifo messageB
if LOCKED is not set to 1 the messages will mix up, otherwise the two threads will take and release the resource correctly.

Ubuntu Semaphore: Segmentation fault (core dumped)

I am learning semaphores in C using Ubuntu right now. The professor just throw us this code and ask us to study it and observe. When I compiled I get a warning that ctime(&sem_buf.sem_ctime) returns an int, not a char * but nothing major. When I run it the output is just: Semaphore identifier: 0 Segmentation fault (core dumped). I am very confused as of what went wrong and I have no idea what is going on in this code. Some help would be very much appreciated.
Here is the code:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
# define NS 3
union semun {
int val;
struct semid_ds *buf;
ushort *array; // Unsigned short integer.
};
int main(void)
{
int sem_id, sem_value, i;
key_t ipc_key;
struct semid_ds sem_buf;
static ushort sem_array[NS] = {3, 1, 4};
union semun arg;
ipc_key = ftok(".", 'S'); // Creating the key.
/* Create semaphore */
if ((sem_id = semget(ipc_key, NS, IPC_CREAT | 0666)) == -1) {
perror ("semget: IPC | 0666");
exit(1);
}
printf ("Semaphore identifier %d\n", sem_id);
/* Set arg (the union) to the address of the storage location for */
/* returned semid_ds value */
arg.buf = &sem_buf;
if (semctl(sem_id, 0, IPC_STAT, arg) == -1) {
perror ("semctl: IPC_STAT");
exit(2);
}
printf ("Create %s", ctime(&sem_buf.sem_ctime));
/* Set arg (the union) to the address of the initializing vector */
arg.array = sem_array;
if (semctl(sem_id, 0, SETALL, arg) == -1) {
perror("semctl: SETALL");
exit(3);
}
for (i=0; i<NS; ++i) {
if ((sem_value = semctl(sem_id, i, GETVAL, 0)) == -1) {
perror("semctl : GETVAL");
exit(4);
}
printf ("Semaphore %d has value of %d\n",i, sem_value);
}
/*remove semaphore */
if (semctl(sem_id, 0, IPC_RMID, 0) == -1) {
perror ("semctl: IPC_RMID");
exit(5);
}
}
You need to include time.h to the compiler recognize ctime function. The warning is because the compiler don't know ctime is a function and that returns an char*. By default GCC assumes the unknown function returns an int.

Resources