/*
* locking.c
* This program demonstrates how to use the file locking
* features.
*
* to compile: cc -O -pipe locking.c -o locking
*
*/
#include <stdio.h>
#include <errno.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/file.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <unistd.h>
#include <fcntl.h>
#define MODE (S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH)
#define MAX_TIME (60 * 60 * 2)
#define MONKEY_BOOK ("monkey_book.out")
#define PAGE_END ("\n\n----------------------END-OF-PAGE-----------------------\n\n")
#define END_LEN (60)
#define PAGE_LEN (500 * 4)
#define LOCK_LEN (PAGE_LEN + END_LEN);
#define LETTERS (" abcdefghijklmnopqrstuvwxyz\n ABCDEFGHIJKLMNOPQRSTUVWXYZ.! \n ")
/*
* To use FLOCK just uncomment the line below. Otherwise
* comment it out to use the fcntl function instead.
*/
/* #define USE_FLOCK */
/* our functions */
void million_monkies(int fd);
static void clean_up(int sig);
static void parent_term(int sig);
/*
* Save the enviroment for a signal return to
* clean up.
*/
jmp_buf env;
int main(int argc, char **argv)
{
int children, fd, i;
struct rlimit limit;
/*
* Get our args
*/
if( argc > 1 )
{
children = atoi(argv[1]);
/* get our limits */
if( getrlimit(RLIMIT_NPROC, &limit) == 0 )
{
/* Check to see if we are under our limits */
if( children < limit.rlim_max )
{
/* open our file */
fd = open(MONKEY_BOOK, (O_RDWR | O_CREAT), MODE );
if( fd > 0 )
{
/* Lets get those monkies typing ! */
for( i = 0; i < children; i++ )
{
if( fork() == 0 )
{
signal(SIGHUP, clean_up);
million_monkies(fd);
close(fd);
} /* if(fork) */
} /* for */
/* set the parent's signals */
signal(SIGHUP, SIG_IGN);
signal(SIGINT, parent_term);
signal(SIGTERM, parent_term);
signal(SIGKILL, parent_term);
if( setjmp(env) == 0 )
{
sleep(MAX_TIME);
/* Exciting: Here we have a use for the raise call ! */
raise(SIGTERM);
}
else
{
printf("\nSignal recieved, killing off children \n");
kill(0, SIGHUP);
/*
* now we have to wait for our children
*/
while( waitpid(-1, (int *)NULL, 0) > 0 )
{
;
}
}
} /* if( fd ) */
else
{
printf("ERROR ! cannot open %s\n", MONKEY_BOOK );
}
} /* if( children ) */
else
{
printf("ERROR ! rlimits nproc is %u \n", limit.rlim_max );
}
} /* if( getrlimit ) */
else
{
printf("ERROR ! the call to getrlimit failed \n");
}
} /* if( argc ) */
else
{
printf("ERROR ! you need to supply and interger \n");
}
/* FIN */
return(0);
}
#ifndef USE_FLOCK
/*
* They will each lock the file, and write a
* page.
*/
void million_monkies(int fd)
{
int i, len;
char buff[PAGE_LEN], *letters = LETTERS;
struct flock lock;
/* seed our random generator */
srand( (time(NULL) - getpid()) / getpid() );
len = strlen(letters);
while( 1 )
{
for( i = 0; i < PAGE_LEN; i++ )
{
buff[i] = letters[ (rand() % len) ];
}
/*
* Fill out our flock structure. Note
* that we are just going to the end of the
* file for our lock.
*/
lock.l_len = LOCK_LEN;
lock.l_pid = getpid();
lock.l_start = 0;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_END;
/* we will wait untill the lock is granted */
if( fcntl(fd, F_SETLK, &lock) == 0 )
{
/* we have the lock now write to it */
printf("FCNTL lock granted, Process [ %d ] writing \n", getpid() );
write(fd, buff, PAGE_LEN);
write(fd, PAGE_END, END_LEN);
/* now unlock it */
lock.l_type = F_UNLCK;
if( fcntl(fd, F_SETLK, &lock) != 0 )
{
perror("Error unlocking the file\n");
}
} /* if( fcntl) */
usleep( (rand() % getpid()) * 100 );
} /* while(1) */
}
#endif
#ifdef USE_FLOCK
/*
* Same as above except we use flock. As you can
* see the function is much cleaner
*/
void million_monkies(int fd)
{
int i, len;
char buff[PAGE_LEN], *letters = LETTERS;
/* seed our random generator */
srand( (time(NULL) - getpid()) / getpid() );
len = strlen(letters);
while( 1 )
{
for( i = 0; i < PAGE_LEN; i++ )
{
buff[i] = letters[ (rand() % len) ];
}
/* now lock the file and write our data */
if( flock(fd, LOCK_EX) == 0 )
{
/* we have the lock now write to the file */
printf("FLOCK granted, Process [ %d ] writing \n", getpid() );
write(fd, buff, PAGE_LEN);
write(fd, PAGE_END, END_LEN);
/* now unlock it */
if( flock(fd, LOCK_UN) != 0 )
{
perror("Error unlocking the file\n");
}
} /* if(flock) */
usleep( (rand() % getpid()) * 100 );
} /* while */
}
#endif
/*
* Child's exit function.
* Actually an empty function, used to demonstrate signal
* usage.
*/
static void clean_up(int sig)
{
/*
* Do nothing, just used to interupt the process.
* Once we return, we can clean up nicely.
*/
}
/*
* Parents exit function
*/
static void parent_term(int sig)
{
/* return and clean up */
longjmp(env, sig);
}
syntax highlighted by Code2HTML, v. 0.9