mirror of
https://github.com/LIV2/libnix.git
synced 2025-12-06 00:23:08 +00:00
285 lines
8.1 KiB
C
285 lines
8.1 KiB
C
#include "stdio.h"
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include <devices/timer.h>
|
|
#include <dos/dosextens.h>
|
|
#include <proto/exec.h>
|
|
#include "debuglib.h"
|
|
#include "select.h"
|
|
#include "socket.h"
|
|
#include "stabs.h"
|
|
|
|
/*
|
|
**
|
|
*/
|
|
static struct MsgPort *_tport=NULL;
|
|
static struct timerequest *_treq=NULL;
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void __setupselect(void)
|
|
{
|
|
if (((_tport=CreateMsgPort())==NULL) ||
|
|
((_treq=CreateIORequest(_tport,sizeof(*_treq)))==NULL))
|
|
exit(20);
|
|
}
|
|
ADD2INIT(__setupselect,-10);
|
|
|
|
void __cleanupselect(void)
|
|
{
|
|
if (_treq) {
|
|
DeleteIORequest(_treq); _treq=NULL;
|
|
}
|
|
|
|
if (_tport) {
|
|
DeleteMsgPort(_tport); _tport=NULL;
|
|
}
|
|
}
|
|
ADD2EXIT(__cleanupselect,-10);
|
|
|
|
/*
|
|
**
|
|
*/
|
|
#if 0
|
|
static inline void handle_select_port(void)
|
|
{ extern struct MsgPort *__selport;
|
|
struct StandardPacket *pkt;
|
|
|
|
while((pkt=GetPacket(__selport))) {
|
|
DB( BUG("handle_select_port got packet %lx\n", pkt); )
|
|
pkt->sp_Pkt.dp_Port = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static inline void setcopy(int nfd, u_int *ifd, u_int *ofd)
|
|
{
|
|
/* this procedure is here, because it's "normal" that if you only
|
|
* want to select on fd 0,1,2 eg. you only pass a long to select,
|
|
* not a whole fd_set, so we can't simply copy over results in the
|
|
* full size of an fd_set.. */
|
|
|
|
/* we have to copy that many longs... */
|
|
for (nfd=(nfd+31)>>5; nfd; *ofd++=*ifd++,--nfd);
|
|
}
|
|
|
|
static inline int net_select(int s, fd_set *in, fd_set *out, fd_set *exc, struct timeval *timeout, u_long *sigs)
|
|
{ struct SocketSettings *lss;
|
|
int rc;
|
|
|
|
switch (lss=_lx_get_socket_settings(),lss->lx_network_type) {
|
|
case LX_AS225:
|
|
rc = SOCK_selectwait(s, in, out, exc, timeout, sigs);
|
|
break;
|
|
|
|
case LX_AMITCP:
|
|
rc = TCP_WaitSelect(s, in, out, exc, timeout, (ULONG*)sigs);
|
|
break;
|
|
|
|
default:
|
|
rc = -1;
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static inline int lx_select(int nfd, fd_set *ifd, fd_set *ofd, fd_set *efd, struct timeval *timeout, u_long *mask)
|
|
{ int i, waitin, waitout, waitexc, dotout, result, skipped_wait;
|
|
u_long net_nfds, wait_sigs, recv_wait_sigs=0, origmask = mask ? *mask : 0;
|
|
StdFileDes *f;
|
|
|
|
/* as long as I don't support anything similar to a network, I surely
|
|
* won't get any exceptional conditions, so *efd is mapped into
|
|
* *ifd, if it's set.
|
|
*/
|
|
|
|
/* first check, that all included descriptors are valid and support
|
|
* the requested operation. If the user included a request to wait
|
|
* for a descriptor to be ready to read, while the descriptor was only
|
|
* opened for writing, the requested bit is immediately cleared
|
|
*/
|
|
waitin = waitout = waitexc = 0;
|
|
/*if (nfd > NOFILE) nfd = NOFILE;*/
|
|
|
|
for (i = 0; i < nfd; i++) {
|
|
if (ifd && FD_ISSET(i, ifd) && (f = _lx_fhfromfd(i))) {
|
|
if (!f->lx_fx)
|
|
FD_CLR(i, ifd);
|
|
else
|
|
++waitin;
|
|
}
|
|
|
|
if (ofd && FD_ISSET(i, ofd) && (f = _lx_fhfromfd(i))) {
|
|
if (!f->lx_fx)
|
|
FD_CLR(i, ofd);
|
|
else
|
|
++waitout;
|
|
}
|
|
|
|
if (efd && FD_ISSET(i, efd) && (f = _lx_fhfromfd(i))) {
|
|
/* question: can an exceptional condition also occur on a
|
|
* write-only fd?? */
|
|
if (!f->lx_fx)
|
|
FD_CLR(i, efd);
|
|
else
|
|
++waitexc;
|
|
}
|
|
}
|
|
|
|
dotout = (timeout && timerisset(timeout));
|
|
|
|
for (skipped_wait = 0; ; skipped_wait=1) {
|
|
fd_set readyin, readyout, readyexc;
|
|
fd_set netin, netout, netexc;
|
|
extern int network_installed;
|
|
int tout, readydesc, cmd;
|
|
|
|
FD_ZERO(&readyin);
|
|
FD_ZERO(&readyout);
|
|
FD_ZERO(&readyexc);
|
|
|
|
if (network_installed) {
|
|
FD_ZERO(&netin);
|
|
FD_ZERO(&netout);
|
|
FD_ZERO(&netexc);
|
|
net_nfds = 0;
|
|
}
|
|
|
|
// handle_select_port();
|
|
|
|
tout = readydesc = 0;
|
|
|
|
wait_sigs = SIGBREAKF_CTRL_C | origmask;
|
|
|
|
if ((cmd=SELCMD_POLL,skipped_wait) != 0) {
|
|
|
|
if (dotout) {
|
|
_treq->tr_node.io_Command = TR_ADDREQUEST;
|
|
_treq->tr_time.tv_sec = timeout->tv_sec;
|
|
_treq->tr_time.tv_usec = timeout->tv_usec;
|
|
SendIO(&_treq->tr_node);
|
|
/* clear the bit, it's used for sync packets too, and might be set */
|
|
SetSignal (0, 1 << _tport->mp_SigBit);
|
|
wait_sigs |= 1 << _tport->mp_SigBit;
|
|
}
|
|
|
|
/* have all watched files get prepared for selecting */
|
|
for (i = 0; i < nfd; i++) {
|
|
if (ifd && FD_ISSET (i, ifd) && (f = _lx_fhfromfd(i)))
|
|
wait_sigs |= f->lx_fx->lx_select (f, SELCMD_PREPARE, SELMODE_IN, &netin, &net_nfds);
|
|
if (ofd && FD_ISSET (i, ofd) && (f = _lx_fhfromfd(i)))
|
|
wait_sigs |= f->lx_fx->lx_select (f, SELCMD_PREPARE, SELMODE_OUT, &netout, &net_nfds);
|
|
if (efd && FD_ISSET (i, efd) && (f = _lx_fhfromfd(i)))
|
|
wait_sigs |= f->lx_fx->lx_select (f, SELCMD_PREPARE, SELMODE_EXC, &netexc, &net_nfds);
|
|
}
|
|
|
|
/* now wait for all legally possible signals, this includes BSD
|
|
* signals (but want at least one signal set!)
|
|
*/
|
|
if (network_installed) {
|
|
int res;
|
|
DB( BUG("Calling _net_select, signals are %lx\n", wait_sigs); )
|
|
res = net_select(net_nfds, &netin, &netout, &netexc, NULL, &wait_sigs);
|
|
recv_wait_sigs = wait_sigs;
|
|
DB( BUG("Net select returns %ld, wait_sigs are %lx\n", res, wait_sigs); )
|
|
}
|
|
else
|
|
while (!(recv_wait_sigs = Wait (wait_sigs))) ;
|
|
|
|
if (mask)
|
|
*mask = recv_wait_sigs & origmask;
|
|
|
|
if (dotout) {
|
|
/* IMPORTANT: unqueue the timer request BEFORE polling the fd's,
|
|
* or __wait_packet() will treat the timer request
|
|
* as a packet...
|
|
*/
|
|
if (!CheckIO(&_treq->tr_node))
|
|
AbortIO(&_treq->tr_node);
|
|
else
|
|
recv_wait_sigs |= 1 << _tport->mp_SigBit;
|
|
WaitIO(&_treq->tr_node);
|
|
}
|
|
|
|
// handle_select_port();
|
|
|
|
cmd = SELCMD_CHECK;
|
|
}
|
|
|
|
/* no matter what caused Wait() to return, wait for all requests
|
|
* to complete (we CAN'T abort a DOS packet, sigh...)
|
|
*/
|
|
|
|
/* collect information from the file descriptors */
|
|
for (i = 0; i < nfd; i++) {
|
|
if (ifd && FD_ISSET (i, ifd) && (f = _lx_fhfromfd(i))
|
|
&& f->lx_fx->lx_select (f, cmd, SELMODE_IN, &netin, NULL)) {
|
|
DB( BUG("Select: fd %ld, has data ready for reading\n", i); )
|
|
FD_SET (i, &readyin);
|
|
++readydesc;
|
|
}
|
|
|
|
if (ofd && FD_ISSET (i, ofd) && (f = _lx_fhfromfd(i))
|
|
&& f->lx_fx->lx_select (f, cmd, SELMODE_OUT, &netout, NULL)) {
|
|
DB( BUG("Select: fd %ld, has data ready for writing\n", i); )
|
|
FD_SET (i, &readyout);
|
|
++readydesc;
|
|
}
|
|
|
|
if (efd && FD_ISSET (i, efd) && (f = _lx_fhfromfd(i))
|
|
&& f->lx_fx->lx_select (f, cmd, SELMODE_EXC, &netexc, NULL)) {
|
|
DB( BUG("Select: fd %ld, has an exception\n", i); )
|
|
FD_SET (i, &readyexc);
|
|
++readydesc;
|
|
}
|
|
}
|
|
|
|
/* we have a timeout condition, if readydesc == 0, dotout == 1 and
|
|
* end_time < current time
|
|
*/
|
|
|
|
DB( BUG("After loop, readydesc is %ld\n", readydesc); )
|
|
|
|
if (!readydesc && dotout)
|
|
tout = recv_wait_sigs & (1 << _tport->mp_SigBit);
|
|
|
|
DB( BUG("readydesc is %ld, tout is %ld, timeout is %lx\n", readydesc, tout, timeout); )
|
|
|
|
if (readydesc || tout || (timeout && !timerisset(timeout))) {
|
|
if (ifd) setcopy(nfd, (u_int *)&readyin, (u_int *)ifd);
|
|
if (ofd) setcopy(nfd, (u_int *)&readyout, (u_int *)ofd);
|
|
if (efd) setcopy(nfd, (u_int *)&readyexc, (u_int *)efd);
|
|
result = readydesc; /* ok for tout, since then readydesc is already 0 */
|
|
DB( BUG("Breaking out of loop, result is %ld\n", result); )
|
|
break;
|
|
}
|
|
|
|
if (recv_wait_sigs & SIGBREAKF_CTRL_C) {
|
|
DB( BUG("Found CTRL-C\n"); )
|
|
/* clear it and resend it so the outer stuff can catch it */
|
|
SetSignal(0, SIGBREAKF_CTRL_C);
|
|
Signal(FindTask(NULL), SIGBREAKF_CTRL_C);
|
|
result = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (recv_wait_sigs == (u_long)-1)
|
|
return -1;
|
|
|
|
/* have to set this here, since errno can be changed in signal handlers */
|
|
if (result == -1)
|
|
errno = EINTR;
|
|
|
|
DB( BUG("SELECT: returning %ld\n", result); )
|
|
return result;
|
|
}
|
|
|
|
int select(int nfd, fd_set *ifd, fd_set *ofd, fd_set *efd, struct timeval *timeout)
|
|
{ return lx_select(nfd, ifd, ofd, efd, timeout, NULL); }
|