Code:
#include <sys/wait.h> /* waitpid */
#include <sys/time.h>
#include <signal.h> /* kill */
#include <time.h> /* time */
#include <sched.h> /* sched_yield clone*/
#include <sys/types.h> /* open waitpid kill*/
#include <sys/stat.h> /* open */
#include <unistd.h> /* sleep */
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h> /* errno */
struct arguments{
int fd;
char ch;
int chars;
unsigned int sle;
long int start;
};
typedef struct arguments Arguments;
int lock(const char *lockname)
{
while (1)
{
int fd = open (lockname,O_CREAT|O_RDWR|O_EXCL,0666);
//sleep(1);
if (fd<0)
{
if (errno==EEXIST) //Lock is busy
{
sched_yield();
}
else
{
printf("BAD OPEN LOCK\n");
return -1;
}
}
else
{
return fd;
}
}
}
int unlock (char *lockname, int fd)
{
int ret=close(fd);
if (ret<0)
printf("Lock doesn't exist\n");
unlink(lockname);
return ret;
}
int clone_f(void *args)
{
pid_t pid=getpid();
Arguments *a=(Arguments *)args;
printf("HELLO! I'm the clone having pid=%d and i will write %d times the char'%c' into the file having fd=%d.I'll sleep %u secs between successive writes.\n",(int)pid,a->chars,a->ch,a->fd,a->sle);
int i,fdlock;
long int moment;
for (i=0;i<a->chars;i++)
{
if ((fdlock=lock("LOCK"))<0)
{
return 1;
}
moment=time(NULL)-(a->start);
if (write(a->fd,&moment,sizeof(long int))!=sizeof(long int))
{
printf("Problem while writing moment\n");
return 1;
}
if (write(a->fd,&(a->ch),1)!=1)
{
printf("Problem while writing the char\n");
return 1;
}
printf("[CLONE %d] has written [%ld]%c in file\n",(int)pid,moment,a->ch);
if (unlock ("LOCK",fdlock)<0)
return 1;
sleep(a->sle);
}
return 0;
}
int main (void)
{
int fd;
//Create the file
if ((fd=open("./trial",O_CREAT|O_TRUNC|O_RDWR,0666))==-1)
{
printf ("BAD FILE OPEN\n");
return 1;
}
printf("FILE HAS FD=%d\n",fd);
pid_t cl1,cl2;
int stack1[1024],stack2[1024];
unsigned int sl_t1=2,sl_t2=2;
int chars1=20,chars2=50;
char c1='a',c2='b';
long int start=time(NULL);
Arguments arg1={fd,c1,chars1,sl_t1,start}, arg2={fd,c2,chars2,sl_t2,start};
//Create clones
if ( (cl1=clone(clone_f,&stack1[1023],CLONE_VM|CLONE_FILES,&arg1))==-1)
{
printf("Bad clone 1\n");
return 1;
}
printf("CLONE 1 has pid %d\n",(int)cl1);
if ( (cl2=clone(clone_f,&stack2[1023],CLONE_VM|CLONE_FILES,&arg2))==-1)
{
printf("Bad clone 2\n");
return 1;
}
printf("CLONE 2 has pid %d\n",(int)cl2);
//Wait clones for maximum 60 sec
int tokill[2]={1,1}; //set both the clones to be killed explicitly
pid_t pid;
int i;
for (i=0;i<60;i++)
{
pid=waitpid(-1,NULL,WNOHANG|__WCLONE);
if (pid>0) //One clone terminated
{
if (pid==cl1)
{
tokill[0]=0;//First clone terminated
printf("clone 1 has finished\n");
}
else
{
tokill[1]=0;//Second clone term.
printf("clone 2 has finished\n");
}
}
sleep(1);
}
/*
********** other possibility: just sleep(60) and then kill(pid,SIGKILL) in any case
*/
if (tokill[0]==1) { kill(cl1,SIGKILL); printf("clone 1 has been killed\n");}
if (tokill[1]==1) { kill(cl2,SIGKILL); printf("clone 1 has been killed\n");}
// print file
lseek(fd,0,SEEK_SET);
long int t; char ch;
while (read(fd,&t,sizeof(long int))==sizeof(long int))
{
if (read(fd,&ch,1)==1)
printf("[%ld]%c\n",t,ch);
else
{
printf("unexpected end of file\n");
return 1;
}
}
printf("ENDING..\n");
close(fd);
return 0;
}
As you can see, I implemented lock() and unlock() on my own, following an example by my professor. I commented the sleep(1) in the lock which I found in the example, since i didn't understand its need.. Furthermore, I thought (and running the program including this sleep confirmed this) that it could cause a bad synchronization in the writes..