1
0
Files
irix-657m-src/irix/kern/sgi/select.c
2022-09-29 17:59:04 +03:00

962 lines
22 KiB
C

/*
* Copyright 1989 Silicon Graphics, Inc. All rights reserved.
*
* SGI implementation of select.
*/
#ident "$Revision: 1.112 $"
#include <sys/types.h>
#include <sys/atomic_ops.h>
#include <sys/debug.h>
#include <sys/errno.h>
#include <ksys/vfile.h>
#include <sys/param.h>
#include <sys/sema.h>
#include <sys/pda.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <ksys/vproc.h>
#include <sys/prctl.h>
#include <sys/systm.h>
#include <sys/ktime.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/callo.h>
#include <sys/kmem.h>
#include <sys/cmn_err.h>
#include <sys/splock.h>
#include <sys/sat.h>
#include <sys/schedctl.h>
#include <sys/xlate.h>
#include <ksys/fdt.h>
#include <sys/vsocket.h>
static int dopoll(int, struct pollfd *, struct timeval *, int *, int);
void
initpollhead(struct pollhead *php)
{
bzero (php, sizeof(*php));
spinlock_init(&php->ph_lock, "ph_lock");
}
void
destroypollhead(struct pollhead *php)
{
struct polldat *pdp;
/*
* free any distributed events
*/
while (pdp = php->ph_next) {
php->ph_next = pdp->pd_next;
kmem_free(pdp, sizeof(*pdp));
}
spinlock_destroy(&php->ph_lock);
}
/*
* the function to be placed in the callout table to time out a process
* waiting on poll.
*
* XXX This routine is *not* declared "static" so it may be called from the
* XXX DCE DFS code. This is a *really ugly* situation and should be fixed.
* XXX See bug #550656, ``DCE DFS vs. select/poll [private] interfaces.''
*/
void
polltime(uthread_t *ut)
{
int s = mutex_spinlock(&ut->ut_pollrotorlock);
sv_signal(&UT_TO_KT(ut)->k_timewait);
mutex_spinunlock(&ut->ut_pollrotorlock, s);
}
/*
* Masks for ut_pollrotor. We keep track of how many wakeups have been done
* on the process thread while it was asleep. If we have only had one, then
* the dopoll() code will just pickup the rotor fd status and return. This
* helps processes like the X server that poll on a large # of fds with only
* one or two ever active from instant to instant.
*/
#define ROTORFDMASK 0x3FFF
#define ROTORONCE 0x4000
#define ROTORMULTI 0xC000
/*
* This function initializes a polldat structure with the given data and
* places it on the passed pollhead's list.
*/
static __inline int
_polladd(struct pollhead *php, short events, unsigned int gen,
void *arg, struct polldat *pdp)
{
int s;
ASSERT(php != NULL && pdp != NULL);
pdp->pd_events = events;
pdp->pd_headp = php;
pdp->pd_arg = arg;
s = mutex_spinlock(&php->ph_lock);
if (POLLGEN(php) != gen) {
#pragma mips_frequency_hint NEVER
/*
* If the poll generation number is different than when we
* started, then a pollwakeup has fired.
*/
mutex_spinunlock(&php->ph_lock, s);
return 1;
}
pdp->pd_next = php->ph_list;
php->ph_list = pdp;
php->ph_events |= events;
mutex_spinunlock(&php->ph_lock, s);
return 0;
}
#if CELL_IRIX
/*
* Variation of polladd used by distributed poll implementation.
* Called by I_ routines when they want to queue a thread on a
* pollhead.
*/
#if DEBUG
long polladd_dynamic;
#endif
int
distributed_polladd(struct pollhead *php,
short events,
unsigned int gen)
{
int s;
struct polldat *pdp;
int curpid = current_pid();
int curtid = current_utid();
ASSERT(php != NULL);
s = mutex_spinlock(&php->ph_lock);
if (POLLGEN(php) != gen) {
/*
* If the poll generation number is different than when we
* started, then a pollwakeup has fired.
*/
mutex_spinunlock(&php->ph_lock, s);
return 1;
}
if (pdp = php->ph_next) {
while (pdp) {
if ((pdp->pd_pid == curpid) &&
(pdp->pd_tid == curtid)) {
goto found;
}
pdp = pdp->pd_next;
}
}
mutex_spinunlock(&php->ph_lock, s);
pdp = (struct polldat *)kmem_alloc(sizeof(*pdp), KM_SLEEP);
s = mutex_spinlock(&php->ph_lock);
if (POLLGEN(php) != gen) {
/*
* If the poll generation number is different than
* when we started, then a pollwakeup has fired.
*/
mutex_spinunlock(&php->ph_lock, s);
kmem_free(pdp, sizeof(*pdp));
return 1;
}
pdp->pd_next = php->ph_next;
php->ph_next = pdp;
pdp->pd_events = 0;
#if DEBUG
polladd_dynamic++;
#endif
pdp->pd_headp = php;
pdp->pd_rotorhint = -1;
pdp->pd_pid = curpid;
pdp->pd_tid = curtid;
found:
pdp->pd_events |= events;
mutex_spinunlock(&php->ph_lock, s);
return 0;
}
#endif
/*
* This function removes a polldat structure from a pollhead.
* Recalculate the events after removal of the specified polldat.
*
* Note that we don't hold off interrupts in this routine on a
* single cpu machine. The reason is that we only update the
* linked list on a pollhead in user context (never in interrupt
* context). When we delete ourselves, we do it with a single
* store on the linked list and then update the event masks at
* the very end. This insures that anyone sharing this pollhead
* with us will still get the events they want during the delete.
*/
static __inline void
_polldel(struct polldat *pdp)
{
struct polldat *p, *p2, **pp;
struct pollhead *php;
int events = 0, s;
ASSERT(pdp != NULL);
ASSERT(pdp->pd_headp != NULL);
ASSERT(private.p_kstackflag != PDA_CURINTSTK);
php = pdp->pd_headp;
s = mp_mutex_spinlock(&php->ph_lock);
pp = &php->ph_list;
if ((p = php->ph_list) == NULL) {
/* XXX this should never happen -- remove at start of 6.5.4 */
goto out;
}
do {
p2 = p->pd_next;
if (p == pdp) {
*pp = p2;
} else {
events |= p->pd_events;
pp = &p->pd_next;
}
p = p2;
} while (p);
php->ph_events = events;
pdp->pd_headp = NULL; /* DEBUG */
out:
mp_mutex_spinunlock(&php->ph_lock, s);
}
/*
* XXX We export an out-of-line version of polladd() and polldel() so it may
* XXX be called from the DCE DFS code. This is a *really ugly* situation
* XXX and should be fixed. See bug #550656, ``DCE DFS vs. select/poll
* XXX [private] interfaces.''
*/
int
polladd(struct pollhead *php, short events, unsigned int gen,
void *arg, struct polldat *pdp)
{
return _polladd(php, events, gen, arg, pdp);
}
void
polldel(struct polldat *pdp)
{
_polldel(pdp);
}
/*
* This function applies polldel() to an array of polldat pointers(). The
* start pointer points to the first polldat struct to be deleted. The
* end pointer points one past the last polldat struct to be deleted.
*/
static void
polldelvec(struct polldat *start, struct polldat *end)
{
while (start <= --end)
_polldel(end);
}
/*
* Poll file descriptors for interesting events.
*/
struct polla {
struct pollfd *fdp;
usysarg_t nfds;
sysarg_t timo;
};
/* ARGSUSED */
int
poll(struct polla *uap, rval_t *rvp)
{
struct pollfd p[NPOLLFILE], *pollp;
int psize;
int error;
int fdcnt = 0;
struct rlimit rlim;
struct timeval timeval, *tv;
curuthread->ut_acct.ua_syscps++;
VPROC_GETRLIMIT(curvprocp, RLIMIT_NOFILE, &rlim);
if (uap->nfds > rlim.rlim_cur)
return EINVAL;
/*
* Allocate space for the pollfd array. Then copy in
* the pollfd array from user space.
*/
if (uap->nfds != 0) {
psize = uap->nfds * sizeof(struct pollfd);
if (uap->nfds > NPOLLFILE) {
if ((pollp = kmem_zalloc(psize, KM_SLEEP)) == NULL)
return EAGAIN;
} else {
pollp = p;
}
if (copyin((caddr_t)uap->fdp, (caddr_t)pollp, psize)) {
if (uap->nfds > NPOLLFILE)
kmem_free((caddr_t)pollp, psize);
return EFAULT;
}
}
if (uap->timo < 0)
tv = NULL;
else {
/* get timeval.tv_sec first to avoid overflow */
timeval.tv_sec = uap->timo / 1000; /* msecs to secs */
timeval.tv_usec = (uap->timo - timeval.tv_sec * 1000) * 1000;
tv = &timeval;
}
error = dopoll(uap->nfds, pollp, tv, &fdcnt, 0);
/*
* Don't return EBADF since poll(2) just uses the POLLNVAL flag.
*/
if (error == EBADF) {
error = 0;
}
if (error == 0) {
/*
* Copy out the events and return the fdcnt to the user.
*/
rvp->r_val1 = fdcnt;
if (uap->nfds != 0)
if (copyout((caddr_t)pollp, (caddr_t)uap->fdp, psize))
error = EFAULT;
}
_SAT_PFD_READ2(pollp, uap->nfds, error);
if (uap->nfds > NPOLLFILE)
kmem_free((caddr_t)pollp, psize);
return error;
}
static int
dopoll(int nfds,
struct pollfd *pollp,
struct timeval *atv,
int *fdcnt,
int is_xpg4)
{
uthread_t *ut = curuthread;
struct polldat *darray, *curdat;
struct pollvobj *pollvobj, *pvobj;
toid_t tid, (*callback)(void (*)(), void *, long, ...);
struct pollfd *pfd;
int size, dsize, vsize;
int s, i, rotor, rwonce, vcnt, rv, mayblock;
unsigned int selticks, gen;
int error;
if (atv) {
if (timerisset(atv)) {
/* check to make sure all criteras met,
* before calling fast_timeout
*/
if (kt_needs_fastimer(atv, curthreadp)) {
/* compute interval in fast tick
* need to add 1 to keep from returning early
*/
selticks = fasthzto(atv) + 1;
callback = fast_timeout;
} else {
/* compute interval in normal ticks
* need to add 1 to keep from returning early
*/
selticks = hzto(atv) + 1;
callback = timeout_nothrd;
}
if (selticks == 0)
selticks = 1;
} else
selticks = 0;
}
/*
* Create and initialize the file ptr and polldat data structures.
*/
if (nfds > NPOLLFILE) {
dsize = nfds * sizeof(struct polldat);
vsize = nfds * sizeof(struct pollvobj);
size = dsize + vsize; /* for kmem_free below */
darray = (struct polldat *) kmem_zalloc(size, KM_SLEEP);
ASSERT(darray);
} else {
dsize = NPOLLFILE * sizeof(struct polldat);
vsize = NPOLLFILE * sizeof(struct pollvobj);
size = 0; /* no kmem_free below */
if (ut->ut_polldat == NULL)
ut->ut_polldat = (struct polldat *)
kern_calloc(1, dsize + vsize);
darray = ut->ut_polldat;
}
/*
* Pointer to array of pollvobj structures.
*/
pollvobj = (struct pollvobj *)((char *)darray + dsize);
/*
* Convert fd's to vnode or vocket pointers, and perform fd
* error checking.
*/
error = fdt_select_convert(pollp, nfds, pollvobj);
/*
* If select syscall and bad arguments passed in, get out now
*/
if (error && ut->ut_syscallno == SYS_select - SYSVoffset) {
#pragma mips_frequency_hint NEVER
if (size)
kmem_free((caddr_t)darray, size);
*fdcnt = 0;
return error;
}
/*
* Retry scan of fds until an event is found or until the
* timeout is reached.
*/
vcnt = 0;
ut->ut_pollrotor = 0;
retry:
/*
* Initialize polladd() polldat struct cursor. We hook successive
* polldat's onto pollhead chains as we pass through the array of
* objects to poll. We stop doing this if we ever get a successful
* poll response from an object. We also don't bother doing this if
* a timeout has been specified and there are 0 selticks left since
* we know we aren't going to block.
*/
curdat = darray;
mayblock = !atv || selticks;
/*
* We use a rotor here to cut down on the amount of time spent
* re-adding & deleteing the poll entries on wakeups. It is likely
* that the rotor points to an FD with revents for us. Note that
* when we wakeup, rotor equals 0 if no pollwakeup() has happened,
* or non-zero with a pollp index plus 1. Note that we don't need
* to take the poll rotor lock here because we can not be the target
* of any pollwakeup() or polltime() call at this point.
*/
rotor = ut->ut_pollrotor & ROTORFDMASK;
ASSERT(rotor <= nfds);
rwonce = ut->ut_pollrotor & ROTORMULTI;
ut->ut_pollrotor = 0;
if (rotor)
rotor--;
pfd = &pollp[rotor];
pvobj = &pollvobj[rotor];
for (rv = 0, i = 0; i < nfds; i++) {
struct pollhead *php;
quicktry:
php = NULL;
if (pvobj->pv_vobj != NULL) {
/*
* pvobj refers to either a vnode or a vsocket as
* indicated by the vtype (set by fdt_select_convert):
* 1 => vnode
* 2 => vsocket
*/
ASSERT(pvobj->pv_vtype == 1 || pvobj->pv_vtype == 2);
if (pvobj->pv_vtype == 1) {
vnode_t *vp = (vnode_t *)pvobj->pv_vobj;
static int pollheadalert = 0;
gen = 0;
VOP_POLL(vp, pfd->events, vcnt,
&pfd->revents, &php, &gen, error);
/*
* A little bit of logic to try to catch device
* driver poll() routines which aren't snap-
* shotting the pollhead generation number.
* This portion of the poll() interface was
* added in IRIX 6.5 and this code can probably
* be safely removed in a later version of the
* OS. We don't do it for the VSOP_SELECT()
* below because there's really only one socket
* implementation so far and the entire vsocket
* interface is new with IRIX 6.5.
*/
if (gen == 0 && php != NULL
&& POLLGEN(php) > 1000
&& pollheadalert == 0) {
#pragma mips_frequency_hint NEVER
pollheadalert = 1;
cmn_err_tag(320,CE_ALERT, "dopoll: pollhead"
" generation not set by driver"
" %v?\n", vp->v_rdev);
}
/*
* Hack for xpg4: xopen specifies that a poll
* for exceptional condition on a regular file
* always returns true (as does select for
* READ/WRITE)
*/
if (is_xpg4) {
#pragma mips_frequency_hint NEVER
if ((pfd->events & (POLLPRI|POLLRDBAND))
&& vp->v_type == VREG)
pfd->revents |= pfd->events &
(POLLPRI|POLLRDBAND);
}
} else {
vsock_t *vso = (vsock_t *)pvobj->pv_vobj;
VSOP_SELECT(vso, pfd->events, vcnt,
&pfd->revents, &php, &gen, error);
}
if (error)
goto pollout;
}
if (pfd->revents) {
vcnt++;
mayblock = 0;
rv |= pfd->revents & POLLNVAL;
if (rwonce == ROTORONCE)
goto pollout;
} else if (php == NULL) {
/* if no pollhead, disable ROTORONCE opt */
rwonce = -1;
} else if (mayblock) {
curdat->pd_rotorhint = rotor;
if (_polladd(php, pfd->events, gen,
(void *)ut, curdat) != 0) {
/*
* A pollwakeup() was done after the poll probe.
* We need to retry to recover from this race
* between pollwakeup() and polladd().
*/
goto quicktry;
}
curdat++;
}
if (++rotor >= nfds) {
pfd = pollp;
pvobj = pollvobj;
rotor = 0;
} else {
++pfd;
++pvobj;
}
}
if (!mayblock)
goto pollout;
s = mutex_spinlock(&ut->ut_pollrotorlock);
/*
* If we're going to block and any of our objects didn't give us a
* pollhead to attach to we have to disable the ROTORONCE optimization
* since we'll need to scan the entire array again when we unblock.
*/
if (rwonce < 0)
ut->ut_pollrotor |= ROTORMULTI;
/*
* Since we hold the lock, anybody checking to see if we are on the
* poll synchronization variable will wait until we get there.
*/
if ((ut->ut_pollrotor & ROTORFDMASK) != 0) {
/* a pollwakeup we care about has happened */
mutex_spinunlock(&ut->ut_pollrotorlock, s);
polldelvec(darray, curdat);
goto retry;
}
/*
* If we get here, the poll of fds was unsuccessful. Set a timeout,
* if specified, and block until some fd becomes readable,
* writeable, or gets an exception.
*/
if (atv) {
ASSERT(selticks);
tid = callback(polltime, ut, selticks);
}
rv = sv_wait_sig(&UT_TO_KT(ut)->k_timewait,
(PZERO+1)|TIMER_SHIFT(AS_SELECT_WAIT),
&ut->ut_pollrotorlock, s);
/*
* Delete the timeout if we posted one. If it went off
* while we were asleep, we get back a selticks value of
* zero. In that case, just exit dopoll(). Otherwise,
* save the time tick value returned for the next loop.
*/
if (atv && (selticks = untimeout(tid)) == 0)
goto pollout;
if (rv != -1) {
polldelvec(darray, curdat);
goto retry;
}
error = EINTR;
pollout:
/*
* If select syscall and bad arguments passed in, return EBADF
*/
if (rv == POLLNVAL && ut->ut_syscallno == SYS_select - SYSVoffset) {
#pragma mips_frequency_hint NEVER
error = EBADF;
}
/*
* Poll cleanup code.
*/
if (curdat > darray)
polldelvec(darray, curdat);
if (size)
kmem_free((caddr_t)darray, size);
*fdcnt = vcnt;
return error;
}
/*
* Select system call.
*
*/
struct selecta {
usysarg_t nd;
fd_set *in, *ou, *ex;
struct timeval *tv;
};
static int
k_select(struct selecta *uap, rval_t *rvp, int is_xpg4)
{
struct pollfd po[NPOLLFILE], *pollp;
struct pollfd *pfd;
int nfds = 0, nd = uap->nd, maxnd = fdt_nofiles();
int fdcnt = 0, psize = 0, error = 0;
struct timeval atv;
curuthread->ut_acct.ua_syscps++;
/*
* clamp the max # of fds to the max # open fildes,
* forgiving, if slightly wrong
*/
if (nd > maxnd)
nd = maxnd;
/*
* timeval structure processing
*/
if (uap->tv) {
if (COPYIN_XLATE(uap->tv, &atv, sizeof atv,
irix5_to_timeval_xlate, get_current_abi(), 1)) {
#pragma mips_frequency_hint NEVER
error = EFAULT;
goto out;
}
if (itimerfix(&atv)) {
#pragma mips_frequency_hint NEVER
error = EINVAL;
goto out;
}
/* block indefinitely */
if (atv.tv_sec > 1000000) {
#pragma mips_frequency_hint NEVER
uap->tv = 0;
}
}
/*
* For each fd, if any bits are set convert them into
* the appropriate pollfd struct.
*/
{
ufd_mask_t all, in, ou, ex, bit, *inp, *oup, *exp;
int events, i, j;
/*
* Load the mask pointers
*/
inp = (ufd_mask_t *)uap->in;
oup = (ufd_mask_t *)uap->ou;
exp = (ufd_mask_t *)uap->ex;
for (pfd = pollp = po, i = 0; i < nd; i += NFDBITS) {
/* note: sfu32 sets error to EFAULT on fault */
#define getbits(ptr, var) \
if (ptr) { \
var = sfu32(&error, ptr++); \
}
/*
* Get next set of bits and clamp (mask) down to uap->nd
*/
in = ou = ex = 0;
getbits(inp, in);
getbits(oup, ou);
getbits(exp, ex);
all = in | ou | ex;
if ((nd - i) < NFDBITS) {
all &= (1 << (nd - i)) - 1;
}
#undef getbits
/*
* Loop until we run out of set bits
*/
for (bit = 1, j = i; all != 0; all >>= 1, bit <<= 1, j++) {
if (all & 1) {
/*
* If we run out of local pfd's, allocate a
* max sized buffer to hold all of them.
*
* We postpone this based on the idea that
* a lot of select calls have holey bit args,
* which is the case with the X server.
*/
if (nfds == NPOLLFILE) {
psize = nd * sizeof(struct pollfd);
pollp = kmem_alloc(psize, KM_SLEEP);
bcopy(po, pollp, sizeof po);
pfd = &pollp[NPOLLFILE];
}
/*
* Create new pfd, fill in all fields
*/
pfd->fd = j;
pfd->revents = events = 0;
if (bit & in)
events |= POLLRDNORM;
if (bit & ou)
events |= POLLWRNORM;
if (bit & ex)
events |= POLLPRI|POLLRDBAND;
pfd->events = events;
pfd++;
nfds++;
}
}
}
}
/* If a copy error happened, exit out now */
if (error)
goto out;
/* Call dopoll to check the pollfds for events */
error = dopoll(nfds, pollp, uap->tv ? &atv : NULL, &fdcnt, is_xpg4);
/* Reverse pollfd info back into bit strings (time critical!) */
if (!error) {
ufd_mask_t in = 0, ou = 0, ex = 0, bit;
fd_set *inp = uap->in, *oup = uap->ou, *exp = uap->ex;
int revents, n, j, i;
/* note: spu32 sets error to EFAULT on fault */
#define putbits(ptr, var) \
if (ptr) { \
(void) spu32(&error, &ptr->fds_bits[j], var); \
}
/* this code assumes fd's are always increasing!!! */
for (pfd = pollp, n = 0, j = -1; n < nfds; n++, pfd++) {
ASSERT(pfd->fd >= 0 && pfd->fd <= nd);
i = (unsigned int)pfd->fd / NFDBITS;
bit = 1 << ((unsigned int)pfd->fd % NFDBITS);
if (i != j) {
/* save previous set of bits */
if (j != -1) {
putbits(inp, in);
putbits(oup, ou);
putbits(exp, ex);
in = ou = ex = 0;
}
/* setup for next set */
j = i;
}
if ((revents = pfd->revents) != 0) {
if (revents & (POLLHUP|POLLERR))
revents |= pfd->events;
if (revents & POLLRDNORM)
in |= bit;
if (revents & POLLWRNORM)
ou |= bit;
if (revents & (POLLPRI|POLLRDBAND))
ex |= bit;
}
}
/* save last set on the way out */
if (nfds) {
ASSERT(j >= 0);
putbits(inp, in);
putbits(oup, ou);
putbits(exp, ex);
}
rvp->r_val1 = fdcnt;
#undef putbits
}
out:
_SAT_PFD_READ2(pollp, nfds, error);
if (psize) {
kmem_free((caddr_t)pollp, psize);
}
return error;
}
int
select(struct selecta *uap, rval_t *rvp)
{
return k_select(uap, rvp, 0);
}
int
xpg4_select(struct selecta *uap, rval_t *rvp)
{
/* flag arg of 1 indicates xpg4 calling */
return k_select(uap, rvp, 1);
}
/*
* Wake up processes sleeping in poll/select
* We offer some protection from simultaneous poll and pollwakeup's
* by threading them with polllock
*
* Handles both local cell threads and remote cell threads. The local
* case optimized.
*/
void
pollwakeup(struct pollhead *php, short event)
{
struct polldat *pdp;
int alwaysrun = (event & (POLLHUP|POLLERR));
int s = mutex_spinlock(&php->ph_lock);
/*
* First process local cell threads
*/
for (pdp = php->ph_list; pdp; pdp = pdp->pd_next) {
if (alwaysrun || (pdp->pd_events & event)) {
pollwakeup_thread((uthread_t *)pdp->pd_arg,
pdp->pd_rotorhint);
if (event & POLLWAKEUPONE)
break;
}
}
php->ph_gen++;
#if CELL_IRIX
if (pdp = php->ph_next) {
struct polldat *pdp2, **spdp;
vproc_t *vpr;
struct polldat *pl_next;
/*
* Now process any distributed threads
*
*/
pl_next = NULL;
spdp = &php->ph_next;
while (pdp) {
pdp2 = pdp->pd_next;
if (alwaysrun || (pdp->pd_events & event)) {
*spdp = pdp->pd_next;
pdp->pd_next = pl_next;
pl_next = pdp;
} else {
spdp = &pdp->pd_next;
}
pdp = pdp2;
}
mutex_spinunlock(&php->ph_lock, s);
/*
* Now deliver accumulated poll events
* No longer holding lock because we can sleep
*/
if (pdp = pl_next) {
while (pdp) {
vpr = VPROC_LOOKUP(pdp->pd_pid);
if (vpr) {
VPROC_POLL_WAKEUP (vpr, pdp->pd_tid,
0);
VPROC_RELE(vpr);
}
pdp2 = pdp->pd_next;
kmem_free(pdp, sizeof(*pdp));
pdp = pdp2;
}
}
} else {
mutex_spinunlock(&php->ph_lock, s);
}
#else
mutex_spinunlock(&php->ph_lock, s);
#endif
}
/*
* The client side of pollwakeup
*/
void
pollwakeup_thread(uthread_t *ut, short pd_rotorhint)
{
int s;
/*
* Inform a process thread that an event being
* polled for has occurred.
*/
s=mutex_spinlock(&ut->ut_pollrotorlock);
/*
* Have we recorded a rotor wakeup hint? (or disabled?)
*/
if ((ut->ut_pollrotor & ROTORFDMASK) != 0)
ut->ut_pollrotor |= ROTORMULTI;
else
/*
* Record hint of first file descriptor in
* rotor.
*/
ut->ut_pollrotor = (ROTORONCE |
(pd_rotorhint + 1));
sv_signal(&UT_TO_KT(ut)->k_timewait);
mutex_spinunlock(&ut->ut_pollrotorlock, s);
}
#ifdef CELL_IRIX
/*
* Wakeup any threads in a manner to cause them to retry polling.
* This is used to relocate a pollhead.
*/
void
pollrestart(struct pollhead *php)
{
pollwakeup(php, POLLERR);
}
#endif