4.3BSD/usr/ingres/source/support/ildr.c
/*
* ilwrite() : write driver
* 1. copy Lock request info to lockbuf
* 2. follow action in l_act
* 3. Error return conditions
* -1: lockrequest fails(only on act=1)
* -2: attempt to release a lock not set
* by calling program
* -3: illegal action requested
*/
# include <stdio.h>
# include <sys/param.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <sys/ioctl.h>
# include <errno.h>
# include <ildr.h>
# include <sys/time.h>
# include <netdb.h>
# include <sccs.h>
# define TRUE 1
# define FALSE 0
# ifdef DEBUG
static int ildebug = TRUE;
# endif DEBUG
SCCSID(@(#)ildr.c 8.1 12/31/84)
int From_server; /* read connection from socket server */
long Read_fmt; /* bit mask for select */
char *Prog_name; /* program name for abnormal errors */
extern int errno; /* error number */
/*
** main
** initilize the socket to the socket server, and then sit and on
** a select waiting for input.
*/
main(ac,av)
int ac;
char **av;
{
long read_fd, /* bit mask of useable descriptors*/
num_des; /* number of readable descriptors */
int abnormal(); /* error function */
register int i; /* index */
/*
** close all the files descriptors, so we can have more INGRES
** processes. We are lmited by file descriptors.
*/
# ifdef DEBUG
setbuf(stdout,NULL);
printf("DRIVER: starting up\n");
close(0); /* guarantee that 0 is what is attached to the socket server */
for ( i = 3 ; i < NOFILE ; i++ )
# else
for ( i = 0 ; i < NOFILE ; i++ )
# endif DEBUG
close(i);
/*
** set up all the signals. Catching any signal
** is an error. We do a "warm start" in this condition
*/
for ( i = 0 ; i < NSIG ; i++ )
signal(i,abnormal);
signal(SIGPIPE,SIG_IGN); /* ignore this one, in case a process simply dies in mid stride */
Prog_name = *av;
/*
** if ac == 2, then we are restarted from the the lock driver
** itself, and we don't have to reattach ourselves to the magic
** ingres socket.
*/
if ( ac == 2 )
From_server = 0;
else
From_server = init_socket();
Read_fmt = (1<<From_server);
/*
** infinite loop waiting for something to happen
*/
for ( ;; )
{
read_fd = Read_fmt;
/*
** wake up whenever something happens
*/
while ( (num_des = select(NOFILE,&read_fd,0,0,0)) == 0 )
{
# ifdef DEBUG
printf("select returns 0 (%o)\n",read_fd);
# endif DEBUG
read_fd = Read_fmt;
}
# ifdef DEBUG
printf("select returns %d (%o)\n",num_des,read_fd);
# endif DEBUG
if ( num_des == -1 )
{
# ifdef DEBUG
perror("DRIVER:num_des = -1");
# endif DEBUG
/*
** a bit of defensive programming.
** If there is an EBADF (bad file descriptor) error
** then we assume that a file descriptor has shut down,
** with out tellng us. We go to a function to figure
** out what has died.
*/
if ( errno == EBADF )
close_up(Read_fmt);
sleep(1);
continue;
}
if ( (read_fd & (1<<From_server)) )
{
num_des--;
new_proc();
read_fd &= ~(1<<From_server);
}
if ( num_des > 0 )
{
for ( i = 0 ; i < NOFILE ; i++ )
if ( (read_fd & (1<<i)) )
ilwrite(i);
}
}
}/* main */
/*
** new_proc
** start up a new connection to an Ingres process
*/
new_proc()
{
register int fd;
auto int to_ioctl = 1;
struct sockaddr_in addr;
auto int len;
len = sizeof (addr);
if ( (fd = accept(From_server,&addr,&len)) != -1 )
{
Read_fmt |= (1<<fd);
ioctl(fd,FIONBIO,&to_ioctl);
}
# ifdef DEBUG
else
{
perror("accept");
sleep(1);
}
printf("DRIVER: new file %d (%o)\n",fd,(1<<fd));
# endif DEBUG
}/* new_proc */
ilwrite(read_desc)
register int read_desc;
{
struct Lockreq lockbuf;
register int i;
register int blockflag;
extern int errno;
errno = 0;
# ifdef DEBUG
printf("DRIVER: entering ilwrite, read_desc = %d\n",read_desc);
# endif DEBUG
if ( read(read_desc,&lockbuf, sizeof ( lockbuf)) != sizeof ( lockbuf ) )
{
# ifdef DEBUG
printf("Read error, errno = %d\n",errno);
# endif DEBUG
if ( errno == EWOULDBLOCK )
return;
if ( errno == ECONNRESET )
{
ilrma(read_desc,TRUE);
close(read_desc);
Read_fmt &= ~(1<<read_desc);
return;
}
send_info(read_desc,-5);
return;
}
# ifdef DEBUG
if (ildebug)
printf("ildr: act %d, type %d, mode %d, read_desc %d\n",
lockbuf.lr_act, lockbuf.lr_type, lockbuf.lr_mod, read_desc);
# endif DEBUG
if (( lockbuf.lr_act < A_RLS1)
&& ((lockbuf.lr_type < T_CS) || (lockbuf.lr_type > T_DB )
|| (lockbuf.lr_mod < M_EXCL) || (lockbuf.lr_mod > M_SHARE )))
{
# ifdef DEBUG
printf("Illegal request\n");
# endif DEBUG
send_info(read_desc,-5);
return;
}
/*
* follow action from lock request
*/
switch(lockbuf.lr_act)
{
case A_RTN:
# ifdef DEBUG
if ( ildebug )
printf("Driver: A_RTN\n");
# endif DEBUG
/*
** attempt to set lock.
** error return if failure.
*/
for ( i = 0; i <= lockbuf.lr_type; i++)
{
if (Lockset[i] == 0)
{
# ifdef DEBUG
if (ildebug)
printf("ildr: lock %d not available\n", i);
# endif DEBUG
send_info(read_desc,-1);
return;
}
}
if (ilunique(&lockbuf) >= 0)
{
send_info(read_desc,-1);
return;
}
# ifdef DEBUG
if ( ildebug )
printf("Driver: lock assigned\n");
# endif DEBUG
ilenter(&lockbuf,read_desc);
break;
case A_SLP:
# ifdef DEBUG
if ( ildebug )
printf("Driver: A_SLP\n");
# endif DEBUG
if ( set_lock(read_desc,lockbuf) == -1 )
return;
# ifdef DEBUG
if ( ildebug )
printf("Driver: got lock\n");
# endif DEBUG
break;
case A_RLS1:
/* remove 1 lock */
# ifdef DEBUG
if ( ildebug )
printf("Driver: A_RLS1\n");
# endif DEBUG
if ((i = ilfind(&lockbuf,read_desc)) >= 0)
{
ilrm(i,read_desc);
}
else
{
send_info(read_desc,-2);
return;
}
# ifdef DEBUG
if ( ildebug )
printf("Driver: released\n");
# endif DEBUG
break;
case A_RLSA:
/* remove all locks for this process id*/
# ifdef DEBUG
if ( ildebug )
printf("Driver: A_RLSA\n");
# endif DEBUG
ilrma(read_desc,FALSE);
break;
case A_ABT: /* remove all locks */
# ifdef DEBUG
if ( ildebug )
printf("Driver: A_ABT\n");
# endif DEBUG
ilclose();
break;
default :
# ifdef DEBUG
if ( ildebug )
printf("DRIVER: garbage\n");
# endif DEBUG
send_info(read_desc,-3);
}
send_info(read_desc,0);
}
/*
* ilunique- check for match on key
*
* return index of Locktab if match found
* else return -1
*/
static
ilunique(ll)
register struct Lockreq *ll;
{
register int k;
register struct Lockform *p;
register struct Lockreq *q;
for (k = 0; k < NLOCKS; k++)
{
p = &Locktab[k];
if ((p->l_mod != M_EMTY)
&& (ilcomp(p->l_key,ll->lr_key) == 0)
&& (p->l_type == ll->lr_type)
&& ( (p->l_mod == M_EXCL) || (ll->lr_mod == M_EXCL)) ) {
# ifdef DEBUG
if (ildebug) {
register int i;
printf("ildr: lock ");
for (i = 0; i < KEYSIZE; i++)
printf("%c", ll->lr_key[i]);
printf(" busy\n");
}
# endif DEBUG
return(k);
}
}
return(-1);
}
static
ilfind(ll,key)
register struct Lockreq *ll;
int key;
{
register int k;
register struct Lockform *p;
register struct Lockreq *q;
for (k = 0; k < NLOCKS; k++)
{
p = &Locktab[k];
if ((p->l_mod != M_EMTY)
&& (ilcomp(p->l_key,ll->lr_key) == 0)
&& (p->l_type == ll->lr_type)
&& (p->l_pid == key))
return(k);
}
return(-1);
}/* ilfind */
/*
* remove the lth Lock
* if the correct user is requesting the move.
*/
static
ilrm(l,key,remove_all)
int l;
int key;
int remove_all;
{
register struct Lockform *a;
register k;
a = &Locktab[l];
if (a->l_pid == key && a->l_mod != M_EMTY)
{
if ( !remove_all && a->l_type == T_DB )
return;
a->l_mod = M_EMTY;
a->l_pid = 0;
if (a->l_wflag == W_ON)
{
a->l_wflag = W_OFF;
wakeup(&Locktab[l]);
}
for (k = 0; k <= a->l_type; k++)
{
Lockset[k]++;
if (Lockset[k] == 1)
wakeup(&Lockset[k]);
}
}
}/* ilrm */
/*
* ilrma releases all locks for a given process id(pd)
* -- called from sys1.c$exit() code.
*/
ilrma(key,remove_all)
int key;
int remove_all;
{
register int i;
# ifdef DEBUG
printf("DRVIER: Removing all, key = %d\n",key);
# endif DEBUG
for ( i = 0; i < NLOCKS; i++ )
ilrm(i,key,remove_all);
}
/*
* enter Lockbuf in locktable
* return position in Locktable
* error return of -1
*/
static
ilenter(ll,key)
register struct Lockreq *ll;
int key;
{
int k,l;
register char *f,*t;
register struct Lockform *p;
for (k = 0; k < NLOCKS; k++)
{
p = &Locktab[k];
if (p->l_mod == M_EMTY)
{
p->l_pid = key;
p->l_type = ll->lr_type;
Locktab[k].l_mod = p->l_mod = ll->lr_mod;
f = ll->lr_key;
t = p->l_key;
for (l = 0; l < KEYSIZE; l++)
*t++ = *f++;
for (l = 0; l <= ll->lr_type; l++)
Lockset[l]--;
# ifdef DEBUG
if ( ildebug )
printf("DRIVER: ilenter %d, mod %d, omod = %d\n",k,p->l_mod,Locktab[k].l_mod);
# endif DEBUG
return(k);
}
}
# ifdef DEBUG
if ( ildebug )
printf("DRIVER: ilenter -1\n");
# endif DEBUG
return (-1);
}
/*
* ilcomp- string compare
* returns 0 if strings match
* returns -1 otherwise
*/
static
ilcomp(s1,s2)
register char *s1,*s2;
{
register int k;
for (k = 0; k < KEYSIZE; k++)
if ( *s1++ != *s2++)
# ifdef DEBUG
{
if ( ildebug )
printf("DRIVER: ilcomp returning -1\n");
return ( -1 );
}
# else DEBUG
return (-1);
# endif DEBUG
return (0);
}
/*
* ilclose- releases all locks
*/
static
ilclose()
{
register int k;
register caddr_t c;
# ifdef DEBUG
printf("DRIVER: entered close\n");
# endif DEBUG
for (k = 0; k < NLOCKS; k++)
wakeup( &Locktab[k] );
for (k = 0; k < 4; k++)
wakeup( &Lockset[k]);
for (c = (caddr_t)&Locktab[0].l_pid; c < (caddr_t)&Locktab[NLOCKS];)
*c++ = 0;
Lockset[0] = NLOCKS;
Lockset[1] = PLOCKS;
Lockset[2] = RLOCKS;
Lockset[3] = DLOCKS;
}/* ilclose */
/*
** set_lock
** attempt to set a lock. If we can't, block the process and
** return -1, if we can than set the lock and return 0.
*/
set_lock(read_desc,lockbuf)
register int read_desc;
struct Lockreq lockbuf;
{
register int blockflag;
register int i;
/*
** attempt to set lock.
** sleep on blocking address if failure.
*/
do
{
do
{
blockflag = TRUE;
for ( i = 0; i <= lockbuf.lr_type; i++)
if (Lockset[i] == 0)
{
# ifdef DEBUG
if (ildebug)
printf("ildr: lock %d not available\n", i);
# endif DEBUG
wait_on(read_desc,&Lockset[i],lockbuf);
return(-1);
}
} while (!blockflag);
if (( i = ilunique(&lockbuf)) >= 0 )
{
blockflag = FALSE;
Locktab[i].l_wflag = W_ON;
wait_on(read_desc,&Locktab[i],lockbuf);
return(-1);
}
} while (!blockflag);
ilenter(&lockbuf,read_desc);
return ( 0 );
}/* set_lock */
/*
** send_info
** Send the data down the socket. Don't do it if it would cause the driver
** to block.
*/
send_info(fd,data)
register int fd;
int data;
{
auto int wdes = ( 1<<fd );
struct timeval time;
errno = 0;
time.tv_sec = 10;
time.tv_usec = 0;
if ( select(NOFILE,0,&wdes,0,&time) != 1 )
{
Read_fmt &= ~(1<<fd);
ilrma(fd,TRUE);
close(fd);
}
else
if ( write(fd,&data,sizeof (int)) != sizeof (int) )
{
if ( errno == 0 )
return;
Read_fmt &= ~(1<<fd);
ilrma(fd,TRUE);
close(fd);
}
}/* send_info */
struct Wait {
int wait_fd; /* file descriptor to send lock info to off of */
int wait_lock; /* what lock we are waiting for */
struct Lockreq wait_req; /* the lock request */
struct Wait *next;
};
struct Wait *Wait_queue = NULL;
/*
** wait_on
** Set up to wait for a free lock.
*/
wait_on(fd,lock,req)
register int fd, lock;
struct Lockreq req;
{
register struct Wait *ptr;
char *calloc();
ptr = (struct Wait *)calloc(1,sizeof (struct Wait));
ptr->wait_fd = fd;
ptr->wait_lock = lock;
ptr->wait_req = req;
ptr->next = Wait_queue;
Wait_queue = ptr;
}/* wait_on */
/*
** wakeup
** See if there is anythng waiting on the newly freed lock. If there is,
** tell it it can have the lock now.
*/
wakeup(lock)
register int lock;
{
register struct Wait *ptr,*back;
for ( back = NULL, ptr = Wait_queue ; ptr != NULL ; back = ptr, ptr = ptr->next )
{
if ( ptr->wait_lock == lock )
{
if ( set_lock(ptr->wait_fd,ptr->wait_req) == 0 )
{
send_info(ptr->wait_fd,0);
if ( back != NULL )
back->next = ptr->next;
else
Wait_queue = Wait_queue->next;
cfree(ptr);
return;
}
}
}
}/* wakeup */
/*
** abnormal
** a signal has come down and hit us. We restart the entire
** program, and hope it goes away
*/
abnormal(sig)
int sig;
{
extern int errno;
# ifdef DEBUG
printf("DRIVER: error %d, restarting\n",sig);
# endif
execl("/etc/lock_driver","lock_driver","restart",0);
execl(Prog_name,Prog_name,"restart",0);
execlp("lock_driver","lock_driver","restart",0);
exit(4);
}/* abnormal */
/*
** close_up
** try and find a closed up file descriptor.
*/
close_up(fmt)
long fmt;
{
long rdesc;
register int i;
struct timeval time;
errno = 0;
time.tv_sec = 0;
time.tv_usec = 0;
for ( i = 0 ; i < NOFILE ; i++ )
{
if ( (1<<i) & fmt )
{
rdesc = (1<<i);
if ( select(NOFILE,&rdesc,0,0,&time) == -1 )
{
/*
** the server socket has closed down.
** BOY ARE WE IN TROUBLE
*/
if ( i == From_server )
{
sleep(1);
# ifdef DEBUG
printf("Restarting socket\n");
# endif DEBUG
init_socket();
}
if ( errno == EBADF )
{
shutdown(i,2);
close(i);
Read_fmt &= ~(1<<i);
ilrma(i,TRUE);
}
}
}
}
}/* close_up */