Files
Arquivotheca.SunOS-4.1.4/sys/rfs/queue.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

255 lines
6.3 KiB
C

/* @(#)queue.c 1.1 94/10/31 SMI */
/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
/* #ident "@(#)kern-port:nudnix/queue.c 10.18" */
/*
* q u e u e . c
*
* A msg is the frozen instance of a system call
* that was begun on the local machine and, because it
* referenced a remote file, needs to be completed
* on a remote machine.
*
* Msgs are received by queues. queues either belong to the
* general pool of queues, which is handled as a unit,
* or they are handled individually.
*
* A process can either wait for a msg on a specific queue
* or for any msg from the general pool of queues.
*/
#include <sys/types.h>
#include <rfs/sema.h>
#include <sys/sysmacros.h>
#include <rfs/rfs_misc.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/signal.h>
#include <sys/stream.h>
#include <rfs/comm.h>
#include <sys/user.h>
#include <sys/vnode.h>
#include <rfs/message.h>
#include <rfs/nserve.h>
#include <rfs/rfs_mnt.h>
#include <rfs/recover.h>
#include <sys/proc.h>
#include <sys/debug.h>
#include <rfs/rdebug.h>
#include <rfs/rfs_serve.h>
extern void add_proc();
extern void del_proc();
struct rcvd *msgs = NULL; /* messages waiting for servers */
extern int msglistcnt; /* number of rcvd's on message list */
/*
* de_queue: dequeue a message from the specified queue. handle remote
* signals, wait for a msg to arrive, dequeue the msg.
*/
int
de_queue(rqueue, bufp, new_gift, size, srsig, sdp)
rcvd_t rqueue;
mblk_t **bufp;
sndd_t new_gift;
int *size;
int *srsig; /* Flag for sent remote signal, passed in and out */
sndd_t sdp; /* sd to send remote signal on. If NULL, don't send */
{
int sig = 0;
char cursig = 0;
int s;
extern rcvd_t sigrd;
int error = 0;
int caught_signal;
/* This is where we have to worry about remote signals.
* If we were awakened and return with a 1, we've got
* a signal and a signal message should be sent.
* Otherwise the wakeup was (presumably) because of an incoming
* message.
*/
if (*srsig)
SAVE_SIG(u.u_procp, sig, cursig);
s = splrf();
while (1) {
if (rqueue->rd_stat & RDLINKDOWN) {
(void) splx(s);
RESTORE_SIG(u.u_procp, sig, cursig);
DUPRINT2(DB_GDPERR,"de_queue: lnk down rd %x\n", rqueue);
return(ENOLINK);
}
if (rqueue->rd_qcnt)
break;
caught_signal = psema((caddr_t) &rqueue->rd_qslp, PREMOTE|PCATCH);
if (caught_signal && !*srsig && sdp) {
(void) splx(s);
DUPRINT2(DB_SIGNAL,"de_queue:sig=%x\n",u.u_procp->p_sig);
if (error = du_rsignal(sdp))
return(error);
(*srsig)++;
s = splrf();
}
ACCUM_SIG(u.u_procp, sig, cursig);
}
(void) splx(s);
RESTORE_SIG(u.u_procp, sig, cursig);
(void) dequeue(rqueue,bufp,new_gift,size);
DUPRINT2(DB_COMM, "de_queue: dequeue on rd %x", rqueue);
return(error);
}
/*
* serve_dq:
* Sleep waiting for a message on to arrive on an rd.
* When awoken:
* If caught signal return (and this server dies).
* Else, take message from signal rd, if there is one.
* Else, take message from first available rd.
* Else, if too many idle servers return and die.
* Else, do it again.
*/
rcvd_t
serve_dq(bufp, size, sp)
mblk_t **bufp;
int *size;
register struct serv_proc *sp;
{
int s;
int caught_signal;
extern rcvd_t sigrd;
extern struct timeval time;
extern long rfs_serve_time;
register struct proc *p = sp->s_proc;
extern struct serv_list s_active;
del_proc(sp, &s_active); /* No longer at work */
p->p_sig &= ~(sigmask(SIGTERM) | sigmask(SIGUSR1));
if (p->p_cursig == SIGUSR1 || p->p_cursig == SIGTERM)
p->p_cursig = 0;
while (1) {
s = splrf(); /* Lock out arriving messages' calls to arrmsg() */
/* Discard old rd */
if (sp->s_rdp != (rcvd_t) NULL) {
sp->s_rdp->rd_act_cnt--;
sp->s_rdp = (rcvd_t) NULL;
}
/* If there's a signal message, handle it */
if (sigrd->rd_rcvdq.qc_head != NULL) {
sp->s_rdp = sigrd;
sp->s_rdp->rd_act_cnt++;
(void) splx(s);
if (dequeue(sigrd,bufp,sp->s_sdp,size) == RFS_SUCCESS) {
break;
} else continue;
}
/* Otherwise, if there's a regular message handle that */
if (msgs != NULL) {
sp->s_rdp = msgs;
sp->s_rdp->rd_act_cnt++;
(void) splx(s);
if (dequeue(msgs,bufp,sp->s_sdp,size) == RFS_SUCCESS) {
break;
} else continue;
}
/* No message and more servers than needed so return and die */
if ((s_idle.sl_count + 1) > minserve &&
(time.tv_sec - sp->s_tlast) > rfs_serve_time) {
(void) splx(s);
break;
}
sp->s_tlast = time.tv_sec;
/* Sleep waiting for a message. If caught signal, return and
die. This is the only place servers can be killed. The epid is
reset so that we don't accidentally try to signal this server. */
add_proc(sp, &s_idle);
caught_signal = psema((caddr_t) &sp->s_sleep, PREMOTE|PCATCH);
del_proc(sp, &s_idle);
(void) splx(s);
if (caught_signal)
break;
}
/* This server is going to work on s_rdp */
if (sp->s_rdp) {
add_proc(sp, &s_active);
p->p_cursig = 0;
p->p_sig = 0;
if (s_active.sl_count >= maxserve) /* Last srvr can't sleep */
psignal(p, SIGUSR1);
else if (s_idle.sl_count == 0) /* Adjust # servers */
add_server();
}
return(sp->s_rdp);
}
/*
* add receive queues to the END of the msgs list.
* duplicates are ignored because interrupts on
* different receive descriptors can try to put
* the same receive queue on the msgs list.
*/
add_to_msgs_list(rcvdp)
rcvd_t rcvdp;
{
rcvd_t current;
if (msgs == NULL) {
msgs = rcvdp;
rcvdp->rd_next = NULL;
msglistcnt = 1;
}
else {
current = msgs;
while ((current != rcvdp)
&& (current->rd_next != NULL))
current = current->rd_next;
if (current != rcvdp) {
current->rd_next = rcvdp;
rcvdp->rd_next = NULL;
msglistcnt++;
}
}
return;
}
/*
* remove the queue from the msgs list.
*/
rm_msgs_list(rcvdp)
rcvd_t rcvdp;
{
rcvd_t prev, current;
if (!(rcvdemp(rcvdp)))
return;
if (msgs != NULL) {
prev = current = msgs;
if (msgs == rcvdp) {
msgs = msgs->rd_next;
msglistcnt--;
} else {
while (((current = prev->rd_next) != NULL)
&& (current != rcvdp))
prev = current;
if (current != NULL) {
prev->rd_next = current->rd_next;
msglistcnt--;
}
}
}
return;
}