1
0
Files
2022-09-29 17:59:04 +03:00

707 lines
16 KiB
C

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include "util.h"
#include "lockprocess.h"
extern char *Progname;
extern int Verbose;
static int Quit = 0;
static FILE *Errorfp = NULL;
static void
proc_signal_handler(int sig, int code, struct sigcontext *sc)
{
Quit = 1;
}
static int
modsw ( double *avg_lock_time, long *lock_requests, double *avg_openclose_time,
long *openclose_requests )
{
int fdS, fd9, i;
struct flock flk;
time_t start, end, open_start, open_end;
time_t locksum = 0;
int error = 0;
pid_t pid = getpid();
open_start = time(NULL);
fdS = open ("SYSDB", O_CREAT + O_RDWR, 0666);
if (fdS == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp, "modsw[%d] line %d: open SYSDB: %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
fd9 = open ("v99", O_CREAT + O_RDWR, 0666);
if (fd9 == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp, "modsw[%d] line %d: open v99: %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
start = time(NULL);
/* Lock byte 0 to Read on 1st fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_RDLCK;
i = fcntl (fdS, F_SETLKW, &flk);
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLKW F_RDLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Lock byte 2 to Read on 1st fd */
flk.l_whence = 0;
flk.l_start = 2;
flk.l_len = 1;
flk.l_type = F_RDLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLKW F_RDLCK (2,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Unlock byte 0 on 1st fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_UNLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLK, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLK F_UNLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* -------------------------------*/
/* Lock byte 0 to Write on 2nd fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_WRLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl v99 offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fd9, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl v99 F_SETLKW F_WRLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Lock byte 2 to Write on 2nd fd */
flk.l_whence = 0;
flk.l_start = 2;
flk.l_len = 1;
flk.l_type = F_WRLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl v99 offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fd9, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl v99 F_SETLKW F_WRLCK (2,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Unlock byte 0 on 2nd fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_UNLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl v99 offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fd9, F_SETLK, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl v99 F_SETLK F_UNLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
end = time(NULL);
*lock_requests = *lock_requests + 6;
*avg_lock_time = *avg_lock_time +
((double)(end - start) - *avg_lock_time) / *lock_requests;
locksum += end - start;
/* Close 2nd fd */
close (fd9);
/* Close 1st fd */
close (fdS);
/* -------------------------------*/
fdS = open ("SYSDB", O_CREAT + O_RDWR);
if (fdS == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp, "modsw[%d] line %d: open SYSDB: %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
start = time(NULL);
/* Lock byte 0 to Read on 1st fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_RDLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLKW F_RDLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Lock byte 2 to Read on 1st fd */
flk.l_whence = 0;
flk.l_start = 2;
flk.l_len = 1;
flk.l_type = F_RDLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLKW F_RDLCK (2,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Unlock byte 0 on 1st fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_UNLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLK, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLK F_UNLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
end = time(NULL);
*lock_requests = *lock_requests + 3;
*avg_lock_time = *avg_lock_time +
((double)(end - start) - *avg_lock_time) / *lock_requests;
locksum += end - start;
/* Close 1st fd */
close (fdS);
/* -------------------------------*/
fdS = open ("SYSDB", O_CREAT + O_RDWR);
if (fdS == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp, "modsw[%d] line %d: open SYSDB: %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
start = time(NULL);
/* Lock byte 0 to Read on 1st fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_RDLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLKW F_RDLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Lock byte 2 to Read on 1st fd */
flk.l_whence = 0;
flk.l_start = 2;
flk.l_len = 1;
flk.l_type = F_RDLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLKW F_RDLCK (2,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Unlock byte 0 on 1st fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_UNLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLK, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"modsw[%d] line %d: fcntl SYSDB F_SETLK F_UNLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
end = time(NULL);
*lock_requests = *lock_requests + 3;
*avg_lock_time = *avg_lock_time +
((double)(end - start) - *avg_lock_time) / *lock_requests;
locksum += end - start;
/* Close 1st fd */
close (fdS);
open_end = time(NULL);
*openclose_requests = *openclose_requests + 8;
*avg_openclose_time = *avg_openclose_time +
((double)(open_end - open_start - locksum) - *avg_openclose_time) /
*openclose_requests;
return(0);
ERR:
return (error);
}
static int
final ( double *avg_lock_time, long *lock_requests, double *avg_openclose_time,
long *openclose_requests )
{
int fdS, i;
struct flock flk;
time_t start, end, open_start, open_end;
int error;
pid_t pid = getpid();
open_start = time(NULL);
fdS = open ("SYSDB", O_CREAT + O_RDWR);
if (fdS == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp, "final[%d] line %d: open SYSDB: %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
start = time(NULL);
/* Lock byte 0 to Write on 1st fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_WRLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"final[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"final[%d] line %d: fcntl SYSDB F_SETLKW F_WRLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Lock byte 2 to Write on 1st fd */
flk.l_whence = 0;
flk.l_start = 2;
flk.l_len = 1;
flk.l_type = F_WRLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"final[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLKW, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"final[%d] line %d: fcntl SYSDB F_SETLKW F_WRLCK (2,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
/* Unlock byte 0 on 1st fd */
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_UNLCK;
if (Verbose > 1) {
fprintf(Errorfp,
"final[%d] line %d: fcntl SYSDB offset %d len %d type %s\n",
(int)pid, __LINE__, flk.l_start, flk.l_len,
locktype_to_str(flk.l_type));
}
i = fcntl (fdS, F_SETLK, &flk);
if (i == -1) {
error = errno;
if (errno != EINTR) {
fprintf(Errorfp,
"final[%d] line %d: fcntl SYSDB F_SETLK F_UNLCK (0,1): %s\n",
(int)pid, __LINE__, strerror(error));
}
goto ERR;
}
end = time(NULL);
*lock_requests = *lock_requests + 3;
*avg_lock_time = *avg_lock_time +
((double)(end - start) - *avg_lock_time) / *lock_requests;
/* Close 1st fd */
close (fdS);
open_end = time(NULL);
*openclose_requests = *openclose_requests + 2;
*avg_openclose_time = *avg_openclose_time +
((double)(open_end - open_start - (end - start)) -
*avg_openclose_time) / *openclose_requests;
return(0);
ERR:
return (errno);
}
int
lockprocess(FILE *fp, unsigned seconds)
{
int error = 0;
int i;
double avg_lock_time = (double)0.0;
long lock_requests = (long)0;
double avg_openclose_time = (double)0.0;
long openclose_requests = (long)0;
pid_t pid = getpid();
Errorfp = fp;
if (Verbose > 1) {
fprintf(fp, "lockprocess[%d]: starting run, %d seconds\n",
(int)pid, seconds);
}
(void)signal(SIGINT, proc_signal_handler);
(void)signal(SIGALRM, proc_signal_handler);
if (seconds) {
(void)alarm(seconds);
}
/* This program tries to reproduce a lockd problem found in PDMS */
while ( !Quit && !error ) {
/* Do some locking */
error = 0;
for (i = 0; !Quit && !error && (i < 6); i++) {
error = modsw (&avg_lock_time, &lock_requests, &avg_openclose_time,
&openclose_requests);
}
if (Verbose > 1) {
fprintf(fp, "lockprocess[%d]: Loop completed, error %d\n", (int)pid,
error);
}
if (!error && !Quit) {
error = final (&avg_lock_time, &lock_requests, &avg_openclose_time,
&openclose_requests);
if (Verbose > 1) {
fprintf(fp, "lockprocess[%d]: final pass completed, error %d\n",
(int)pid, error);
}
}
}
if (!error || (error == EINTR)) {
fprintf(Errorfp, "lockprocess[%d] line %d: lock_requests %d "
"avg_lock_time %lf openclose_requests %d avg_openclose_time %lf\n",
(int)pid, __LINE__, lock_requests, avg_lock_time,
openclose_requests, avg_openclose_time);
}
return ((error == EINTR) ? 0 : error);
}
/*
* start a new process and put it onto the supplied process list
*/
pid_t
newprocess(unsigned seconds, proclist_t **plp)
{
pid_t pid;
int error = 0;
int fd[2];
proclist_t *new;
FILE *fp;
if (pipe(fd) == -1) {
perror("newprocess: pipe");
return(-1);
}
switch (pid = fork()) { /* child process */
case 0:
/*
* child process
* catch SIGINT and close the read side of the pipe
*/
(void)close(fd[0]);
if (fcntl(fd[1], F_SETFL, FNONBLOCK) == -1) {
fprintf(stderr,
"newprocess[%d] line %d: fcntl(F_SETFL, FNONBLOCK): %s\n",
(int)getpid(), __LINE__, strerror(errno));
close(fd[1]);
exit(-1);
}
if (!(fp = fdopen(fd[1], "w"))) {
error = errno;
fprintf(stderr, "newprocess[%d] line %d: fdopen: %s\n",
(int)getpid(), __LINE__, strerror(error));
exit ((error == EINTR) ? 0 : error);
}
error = lockprocess(fp, seconds);
fclose(fp);
exit(error);
case -1:
/*
* fork error
* print a messge, close the pipe and return -1
*/
error = errno;
perror("newprocess: fork");
(void)close(fd[0]);
(void)close(fd[1]);
errno = error;
break;
default:
/*
* close the write side of the pipe now that we've successfully
* forked
*/
close(fd[1]);
if (fcntl(fd[0], F_SETFL, FNONBLOCK) == -1) {
perror("fcntl F_SETFL FNONBLOCK");
close(fd[0]);
return(-1);
}
/*
* allocate a new process list entry
*/
if (!(new = malloc(sizeof(proclist_t)))) {
perror("newprocess: malloc");
close(fd[0]);
return(-1);
}
/*
* fill in the process list entry and thread it onto the
* list
*/
new->pl_pid = pid;
new->pl_pipefd = fd[0];
new->pl_next = *plp;
*plp = new;
}
return(pid);
}
static int
get_output(pid_t pid, proclist_t *plist)
{
int status = 0;
char buf[BUFSIZ];
proclist_t *plp = NULL;
int len;
for (plp = plist; plp; plp = plp->pl_next) {
if (pid == plp->pl_pid) {
while ((len = read(plp->pl_pipefd, buf, BUFSIZ)) > 0) {
if (fwrite(buf, sizeof(char), len, stdout) == -1) {
status = errno;
perror("fwrite stdout");
break;
}
}
if (len == -1) {
status = errno;
fprintf(stderr, "error reading pipe for process %d: %s\n",
(int)plp->pl_pid, strerror(errno));
}
}
}
return(status);
}
int
reap_processes(proclist_t *plist)
{
pid_t pid;
int waitstat;
int status = 0;
if (Verbose) {
printf("Waiting for processes to terminate\n");
}
switch(pid = wait(&waitstat)) {
case 0: /* unexpected return value */
fprintf(stderr, "%s: 0 returned by wait\n", Progname);
status = -1;
break;
case -1: /* error or signal */
switch (errno) {
case EINTR:
break;
case ECHILD:
status = errno;
break;
default:
status = errno;
perror("wait");
}
break;
default: /* child process terminated */
if (WIFEXITED(waitstat)) {
status = WEXITSTATUS(waitstat);
fprintf(stderr, "%s: process %d exited: %s\n",
Progname, pid, strerror(status));
} else if (WIFSIGNALED(waitstat)) {
status = WTERMSIG(waitstat);
fprintf(stderr, "%s: process %d terminated on signal: %d\n",
Progname, pid, status);
} else if (WIFSTOPPED(waitstat)) {
status = -1;
fprintf(stderr, "%s: process %d stopped on signal: %d\n",
Progname, pid, WSTOPSIG(waitstat));
} else {
fprintf(stderr, "%s: unknown wait status 0x%x\n", Progname,
waitstat);
}
/*
* find the process in the list and collect
* its messages, if any
*/
status = get_output(pid, plist);
}
return(status);
}