Related
I have a multiclient Server Socket and I want to block the acces for other Clients, when sending "BEG" to the Server. To open the other Clients again, the Client has to send "END" to the Server. While other Clients are blocked off, they only can use "quit" to exit the Server and if they use conditions() they fall asleep.
So other Clients are blocked for the function conditions() if one process used "BEG", but the process himself has still acces to the function.
If I compile my Code, the Server is running, everything is fine but the Mutexe doesn't work.
The Code is going into the if statement of "BEG" and the Mutex should be locked, but other Clients aren't blocked off.
If I connect a second Client, the Client gets kicked if I use conditions().
My question is, why does the mutex not work for other Clients or in generell? How to check if the Mutex is working?
Edit:
Now my Semaphore doesn't block other processes
Edit 2: I found a way, not the best but one. Now some clients are getting kicked from the Server after using one condition().
main.c:
int state = 0;
int beg() {
state = 1;
return 0;
}
int end() {
state = 0;
return 0;
}
int main() {
int pid, t;
char *eingabe, *inputBuffer[BUFSIZE];
char delimiter[] = "\n ";
int rfd = erstelleSocket();
int cfd;
semaphor semID1 = semGET();
semaphor semID2 = semGET2();
marker[0] = 1;
t = semctl(semID1, 1, SETALL, marker);
if (t == -1) {
fprintf(stderr, "Error with marker\n");
}
t = semctl(semID2, 1, SETALL, marker);
if (t == -1) {
fprintf(stderr, "Error with marker\n");
}
while(1){
cfd = accept(rfd, (struct sockaddr *) &client, &client_len);
if (cfd < 0) {
close(cfd);
fprintf(stderr, "connection failed\n");
break;
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "Error in new process creation\n");
}
if (pid == 0) {
bzero(input, sizeof(input));
bytes_read = read(cfd, input, BUFSIZE);
strncat(input, " ", strlen(" "));
input[strcspn(input, "\r\n")] = 0;
while (bytes_read > 0) {
eingabe = strtok(input, delimiter);
int i = 0;
while (eingabe != NULL) {
inputBuffer[i++] = eingabe;
eingabe = strtok(NULL, delimiter);
}
if (strncmp("quit", inputBuffer[0], 4) == 0) {
close(cfd);
break;
}
if (state != 1) {
down(semID2, 0); //down is a function with semop()
}
down(semID1, 0);
conditions(inputBuffer[0],
inputBuffer[1],
inputBuffer[2],
cfd, semID1, shmID);
up(semID1, 0);
if (state != 1) {
up(semID2, 0); //up is a function with semop()
}
bzero(input, sizeof(input));
bytes_read = read(cfd, input, BUFSIZE);
strncat(input, " ", strlen(" "));
input[strcspn(input, "\r\n")] = 0;
close(rfd);
}
}
close(cfd);
}
close(rfd);
}
my condition function:
void conditions(char *eingabehalter1,
char *eingabehalter2,
char *eingabehalter3,
int cfd, int shmID) {
if (strncmp("PUT", eingabehalter1, 3) == 0) {
put(eingabehalter2, eingabehalter3, cfd, shmID);
} else if (strncmp("GET", eingabehalter1, 3) == 0) {
get(eingabehalter2, cfd, shmID);
} else if (strncmp("DEL", eingabehalter1, 3) == 0) {
del(eingabehalter2, cfd, shmID);
} else if (strncmp("BEG", eingabehalter1, 3) == 0) {
beg();
} else if (strncmp("END", eingabehalter1, 3) == 0) {
end();
} else {
write(cfd, "cmd_nonexistent\n", strlen("cmd_nonexistent\n"));
}
}
createSocket.c:
int rfd; // Rendevouz-Descriptor
rfd = socket(AF_INET, SOCK_STREAM, 0);
int option = 1;
setsockopt(rfd,SOL_SOCKET, SO_REUSEADDR, (const void *) &option, sizeof(int));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
int brt = bind(rfd, (struct sockaddr *) &server, sizeof(server));
int lrt = listen(rfd, 5);
return rfd;
}
main.h:
#include "shmmemory.h"
#include "semaphoren.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT 5678
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t client_len;
char input[BUFSIZE];
int bytes_read;
int erstelleSocket();
void conditions(char *eingabehalter1,
char *eingabehalter2,
char *eingabehalter3,
int cfd, int shmID);
int beg();
int end();
unsigned short marker[2];
Your approach cannot work because you're trying to combine fork with threads. fork creates a copy of the parent's address space for each child process, which means that each child process has its own copy of the mutex object. Process-shared mutexes are possible in POSIX, with special attributes, but I suspect even those don't work with fork; they have to be placed in shared memory.
Have you considered creating threads with pthread_create for the service loop? Or else you can implement this entirely using fork (no pthread material). The children can use POSIX named semaphores (sem_open, et al) or possibly, dare I say it, System V IPC.
Also, don't use strtok in multithreaded code, and clearing memory to zero was standardized in 1989's ANSI C as memset(pointer, 0, size). Since that was 31 years ago, it's okay to lay bzero to rest.
The way you initialize the semaphores is wrong for your use case. From the man page of sem_init():
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
If pshared has the value 0, then the semaphore is shared between the
threads of a process, and should be located at some address that is
visible to all threads (e.g., a global variable, or a variable
allocated dynamically on the heap).
If pshared is nonzero, then the semaphore is shared between
processes, and should be located in a region of shared memory
Based on the above explanations from the man page, the things you need change are:
Semaphore declaration
Since you are using semaphores between processes, you need to declare the variable as shared. You can do that via mmap() to create unnamed UNIX semaphore as follows:
sem_t* sem_var = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)
if (sem_var == MAP_FAILED) // Shared memory creation failed.
goto handle_shm_fail;
Semaphore initialization
Since you are using POSIX semaphores, to make your child use the same semaphores, pshared is set to 1 indicating semaphore is shared between processes.
if (sem_init(sem_var, 1, 1) != 0) // Semaphore initialization failed.
goto handle_sem_fail;
NOTE: In your code sem_var is of type sem_t, now it is a pointer to sem_t. Accordingly, you need to update your code.
I am doing a university project, we have to use the Unix system call.
Right now, I'm really struggling to understand if, in my project, there really is a mistake. This is because, while in terminal it compiles and it starts and finishes without error, on xcode I get several errors.
In particular, I get errors when using semaphores.
I'll try to explain what errors, I receive, but since I'm not native English speakers forgive me in advance if I make some mistakes.
First, the program creates a number of child processes with a fork (). It does depending on how many clientei.txt located (i = iterator).
Immediately I block parent with a semaphore, I run the child up to a certain point, then I block it with a semaphore and I restart the parent.
At this point, the parent should read a message sent by his son, call a function to print the content inside a log.txt and restart the son.
Then the child does other things (including erase the message) and it block.
The parent restart, and everything is repeated for subsequent children.
While in terminal synchronization is perfect (everything happens at the right time without error) this both Linux and Mac, about XCode I had several errors:
semop: Resource temporarily unavailable (if I created more than 5 txt)
semop: File too large (if I created more than 2)
with 2 instead gave me two errors:
semop 1: Interrupted system call (this stops after running both processes)
semop 3: Identifier removed (with this in restarting the second process)
is not so much time that I do C then I do not know what to do. I would like first of all to know if I have to worry (so there is an error), or I have to be quiet because it is a bug in xcode.
If there was a mistake I kindly ask you not to ask me to change the code a lot.
This is mainly because they are close to expiring and I can not afford to do it all again.
I also ask you, if you can, to be as clear as possible. I understand enough English, but not as a mother-tongue, I can not always follow the responses here on StackOverflow.
The code is here:
https://www.dropbox.com/s/2utsb6r5d7kzzqj/xcode%2Bterminal.zip?dl=0
this zip contain a small part of the project that has this problem.
the terminal version works. there is a makefile in this version to simplify the compilation.
xcode version does not work. It contains the Debug folder. Indeed xcode, txt files, it does not read from the root folder where the codes are contained in the folder where it creates the compiled. There is a readme in each case with the procedure in detail.
I tried to minimize, I commented all in English.
I removed the code that was not needed, but I added the file with all the include and functions that use.
here the code:
main.c
key_t key, key_2;
int semid, semid_2;
union semun arg;
union semun arg_2;
struct sembuf sb_2 = {0, -1, 0};
char* nome_file;
nome_file = (char*) malloc(sizeof(char*));
int numero_clienti;
//semaphore for all the child
struct sembuf sb[numero_clienti];
int i_c;
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_num = i_c;
sb[i_c].sem_op = -1;
sb[i_c].sem_flg = 0;
}
//cretion of first SEMAPHORE
{
//key creation
if ((key = ftok("cliente0.txt", 'J')) == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
//creation of the semaphore
if ((semid = semget(key, numero_clienti, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
perror("semget");
exit(EXIT_FAILURE);
}
//set value of all child semaphore
for (i_c = 0; i_c < numero_clienti; i_c++) {
arg.val = 0;
if (semctl(semid, i_c, SETVAL, arg) == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
}
}
//cretion of second SEMAPHORE
{
//key creation
if ((key_2 = ftok("cliente1.txt", 'J')) == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
//creation of the semaphore
if ((semid_2 = semget(key_2, 1, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
perror("semget");
exit(EXIT_FAILURE);
}
//set value of parent semaphore
arg_2.val = 0;
if (semctl(semid_2, 0, SETVAL, arg_2) == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
}
while(fd > 0 && pid > 0){
j++;
close(fd);
pid = fork();
if(pid != 0)
{
i++;
sprintf(nome_file, "./cliente%d.txt", i);
fd = open(nome_file, O_RDONLY);
}
switch(pid)
{
//error case
case -1:
{
perror("Error during fork.");
exit(EXIT_FAILURE);
break;
}
//child case
case 0:
{
puts("Child: I'm a child");
messaggio(numero_clienti, j);
puts("Child: I have to do something");
//Start parent
sb_2.sem_op = 1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
//, stop itself
sb[j].sem_op = -1;
if (semop(semid, &sb[j], 1) == -1)
{
perror("semop");
exit(1);
}
printf("Child: I have to do something else %d\n", getpid());
_exit(EXIT_SUCCESS);
break;
}
//parent case
default:
{
puts("Parent: I'm a parent");
//Stop itself
sb_2.sem_op = -1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop padre");
exit(1);
}
puts("Parent: now I can send the message, my child is blocked");
//restart child
sb[j].sem_op = 1;
if (semop(semid, &sb[j], 1) == -1)
{
perror("semop");
exit(1);
}
//stop itself
sb_2.sem_op = -1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
puts("Parent: end of while");
break;
}
}
}
puts("Parent: I can restart all my child");
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_op = 1;
if (semop(semid, &sb[i_c], 1) == -1)
{
perror("semop");
exit(1);
}
}
puts("I wait the end of my child...");
while (wait(NULL) != -1);
puts("All child end");
//remove semaphore I create
if (semctl(semid, 0, IPC_RMID, arg) == -1)
{
perror("semctl");
exit(1);
}
if (semctl(semid_2, 0, IPC_RMID, arg_2) == -1)
{
perror("semctl");
exit(1);
}
puts("FINE");
return 0;
}
cliente.c
#include "cliente.h"
/**
inside this function child do some thing.
1. at this point it give control to parent after it create a message
2. at this point it remove the message
*/
void messaggio(int numero_clienti, int num_j){
key_t key, key_2;
int semid, semid_2;
struct sembuf sb[numero_clienti];
int i_c;
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_num = i_c;
sb[i_c].sem_op = -1;
sb[i_c].sem_flg = 0;
}
struct sembuf sb_2 = {0, -1, 0};
if ((key = ftok("cliente0.txt", 'J')) == -1) {
perror("ftok");
exit(1);
}
if ((semid = semget(key, 1, 0)) == -1) {
perror("semget");
exit(1);
}
if ((key_2 = ftok("cliente1.txt", 'J')) == -1) {
perror("ftok");
exit(1);
}
if ((semid_2 = semget(key_2, 1, 0)) == -1) {
perror("semget");
exit(1);
}
//creation of a message
//1. Restart parent
sb_2.sem_op = 1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
puts("cambio sem");
//stop itself
sb[num_j].sem_op = -1;
if (semop(semid, &sb[num_j], 1) == -1)
{
perror("semop");
exit(1);
}
//here it can move again
puts("remove message");
puts("Figlio: sono tornato attivo, mio padre aspetta");
}
1st you do
nome_file = (char*) malloc(sizeof(char*));
which allocates 4 or 8 bytes (depending on the platform you compile on: 32 or 64bit).
Then you do
sprintf(nome_file, "./cliente%d.txt", i);
The latter writes to invalid memory, as "./cliente%d.txt" is 14+1 characters long plus the potenial number of digits from i if i>9 or and addtional sign if i<0.
To fix this allocate what is needed:
nome_file = malloc(13 + 10 + 1 + 1); /* 13 for the filename,
10 for the digits,
1 for a potential sign,
1 the C-"strings" 0-terminator. */
This is a really ugly bug, which is expected to be the main issue in your code.
Also in the sources (you linked) in function read_line() you allocate memory, which you do not properly initialise, but later depend on its content.
main.c:20
char* myb2 = (char*) malloc(sizeof(char*));
malloc() does not initialise the memory it allocates, so either do:
char * myb2 = calloc(1, sizeof(char*));
of add and addtional call to
memset(mb2, 0, sizeof(char*));
after the call to malloc().
This bug is nasty either.
Also^2 you should build using gcc's options -std=c99 -D_XOPEN_SOURCE.
That is because:
You are using C constructs available from C99 on only. Typically VLAs, so tell the compiler to treat the code as being C99 code by explcitly stating -std=c99
To #define _XOPEN_SOURCE is issued by gcc, for some header you include in your project.
Also^3 you seem to be not necessarily count the correct number of client(file)s, at least not if your files a distributed as per the archive you linked:
main.c:82
system("ls cliente* | wc -l");
Change this to be:
system("ls cliente*.txt | wc -l");
If the bug described above should return more files then there actually are the following code fails as well from a certain value of i on:
main.c:176
fd = open(nome_file, O_RDONLY);
The result of the above operation is NOT tested. The possible invalid fd is used and the infamous undefined behaviour is taking over. Everything can happen.
As a final note: It's mostly never a bug in the tools we are using.
The command semctl always returns -1 (returns "Fail2" in console). What am I doing wrong?
union semun{
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
} forsem;
forsem.val = 0;
int sem;
if((sem= semget(key, 1, 0666 | IPC_CREAT) == -1)) {
fprintf(stderr, "Fail1");
}
if (semctl(sem, 0, SETVAL, forsem) == -1) {
fprintf(stderr, "Fail2");
}
Errno writes Invalid argument
You make a simple mistake: in
if((sem= semget(key, 1, 0666 | IPC_CREAT) == -1)) {
fprintf(stderr, "Fail1");
}
You should write
if((sem= semget(key, 1, 0666 | IPC_CREAT)) == -1) {
fprintf(stderr, "Fail1");
}
Notice the brackets?
By the way, the error is EIDRM because sem is 0 in your code, not Invalid Argument.
Thanks for your answer! It does not matter. The only thing it's not giving error is for semctl with the second argument 0 (number of the semaphore in the semaphore set), if I put 1 or 30 there, it returns -1.
I am doing a Unix, C assignment. I am creating a Server and a Client which will interact with each other. I am not very experienced with TCP/IP programming so I apologize for being slow in advance.
First, I am trying to create a basic layout of my set up. I compile the Client and Server using a Makefile and it works perfectly. However, when I execute the Server, I get this error:
shmget: Invalid argument
I think it is a problem with IPC resources. I am supposed to remove the IPC resources using atexit() but I don't think I am doing it right.
Here is the code for server.c if it helps:
#include "server.h"
int shmid, semid;
struct Shared *shm;
int main() {
key_t shmkey = 0x6060, semkey = 0x6061;
char *s, c;
unsigned short zeros[2] = {0, 0};
int srvrFd, clntFd, clntAdrLen, i; //socket
struct sockaddr_in srvrAddr, clntAddr;
char buf[256];
if(atexit(server_exit) != 0) {
perror("failed to attach atexit()");
_exit(EXIT_FAILURE);
}
/* Create an array of 2 semaphores with key. */
semid = semget(semkey, 2, 0666 | IPC_CREAT);
if (semid < 0) {
perror("semget");
exit(0);
}
/* Set the values of semaphores */
argument.array = zeros;
if (semctl(semid, 0, SETALL, argument) < 0) {
printf("Cannot init semaphore 0.\n");
}
/* Create the segment. */
if ((shmid=shmget(shmkey, sizeof(struct Shared), IPC_CREAT|0666))<0) {
perror("shmget");
exit(1);
}
/* Attach the segment to our data space. */
if ((shm=shmat(shmid, NULL, 0))==(struct Shared *)-1) {
perror("shmat");
exit(1);
}
/* Put some things into the shared memory. */
s = shm->text;
for (c = 'a'; c<= 'z'; c++) {
*s++ = c;
}
*s = '\0';
shm->number = 123;
//socket
srvrFd = socket(AF_INET, SOCK_STREAM, 0);
if(srvrFd < 0) {
perror("socket");
exit(1);
}
srvrAddr.sin_addr.s_addr = htonl(INADDR_ANY);
srvrAddr.sin_port = htons(6060);
if(bind(srvrFd, (struct sockaddr *)&srvrAddr, sizeof(srvrAddr)) < 0) {
perror("bind");
exit(1);
}
listen(srvrFd, 5);
while(1) {
clntAdrLen = sizeof(clntAddr);
clntFd = accept(srvrFd, (struct sockaddr*)&clntAddr, NULL);
if (fork() == 0) { //we're in the child
i = recv(clntFd, buf, sizeof buf, 0);
send(clntFd, buf, i, 0);
close(clntFd);
exit(0);
} else { //we're in the parent
close(clntFd);
}
}
}
void server_exit(void)
{
if(shm != NULL) {
shmdt(shm);
}
if(semid != -1) {
semctl(semid, 0, IPC_RMID);
}
if(shmid != -1) {
shmctl(shmid, IPC_RMID, 0);
}
}
Thanks for reading.
Edit: Definition of structure..
struct Shared {
char text[27];
int number;
} ;
http://linux.die.net/man/2/shmget
Looks like either the segment exists and it's smaller than what you asked for, or you're trying to create a new one, but it's smaller than the system min size (SHMMIN) or greater than max (SHMMAX)
EDIT: Turns out this was it -- it already existed and was smaller than what you were asking for. You must have created it as a size 27, 28, 29, 30, or 31, since it works for 27 but not 32. If you run the unix command line program ipcs, it will show you all your existing shared memory segments:
key shmid owner perms bytes nattch status
0x00000001 0 ec2-user 666 32 0
Then ipcrm -M <key> will delete it.
From what I'm seeing, you likely don't want to use SYS-V shared memory. Use POSIX if you can. Here is a reference for the POSIX Shared Memory interface:
http://man7.org/linux/man-pages/man7/shm_overview.7.html
also check out:
http://www.cs.cf.ac.uk/Dave/C/node27.html
for a guide to both, but I'd prefer POSIX if it's available (and it will be unless you're on a really old system like DEC Alpha)
EDIT: This peace of code is pretty fine (so take it as example of semaphores ;). Bug in my program was in another place - found by my friend.
I have problem with my functions. Sometimes two processes enter into critical section. I can't find problem in this after I spent 10 hours by debugging. On what I should aim? Is there any possibility to have bud in this piece of code?
// lock semaphore
static int P(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; /* P() */
sem_b.sem_flg = 0;
if (semop(sem_id, &sem_b, 1) == -1) {
// error
return(0);
}
return(1);
}
// unlock semaphore
static int V(int sem_id)
{
struct sembuf sem_b[1];
sem_b.sem_num = 0;
sem_b.sem_op = 1; /* V() */
sem_b.sem_flg = 0;
if (semop(sem_id, &sem_b, 1) == -1) {
// error
return(0);
}
return(1);
}
static int set_semval(int sem_id) {
// set to 1 (opened semaphore)
if (semctl(sem_id, 0, SETVAL, 1) == -1) {
// error
return(0);
}
return(1);
}
static int get_val(int sem_id)
{
union semun sem_union;
//sem_union.val = 0; ?
return semctl(sem_id, 0, GETVAL, sem_union);
}
The action loop:
// semaphores init
int mutex;
if ((mutex=semget(key+2, 1, 0666))>=0) {
// semaphore exists
fprintf(stderr,"semaphore exists for key %d\n", key+2);
}
if ((mutex=semget(key+2, 1, 0666 | IPC_CREAT)) == -1) {
exit(EXIT_FAILURE);
}
if (!set_semval(mutex)) {
exit(EXIT_FAILURE);
}
fork() // some times with good conditionals
// in some children
while(1) {
P(mutex);
assert(get_val(mutex)==0); // always ok
action(); // sometimes made by two processes at same time - fault
V(mutex);
}
Pls, feel free to edit my question.
Many thanks
in your 'action loop' what do you do if your semaphore does not exist?
currently your 3rd parameter to semget is 0666 or the PERMISSION_RW constant. You may want to use:
shmget(key, 1, PERMISSION_RW | IPC_CREAT);
this way if your semaphore does not exist it will create one.
So bug was at another place...