Reimplement max_idle without a separate thread

Remove the KillIdle thread.  Add timeout to struct iop, initialized in
io_open().  Obey it in io_input() by passing it to empth_select().  If
empth_select() times out, report that back through io_input() to
recvclient() and player_login().  If player_login() receives a timeout
indication, print a message and terminate the session.  If
recvclient() receives a timeout indication, flash a message to the
player and initiate a shut down the player's session.

Create WIN32 sys/time.h to define struct timeval.  This creates some
conflicts with WIN32 windows.h definitions.  Including windows.h in
show.c and info.c creates conflicts, so remove that.  Modify service.c
to include sys/socket.h instead of windows.h to remove the conflict
with sys/time.h.
This commit is contained in:
Ron Koenderink 2009-02-01 06:22:26 -06:00 committed by Markus Armbruster
parent a7ee69d112
commit 08b9455682
17 changed files with 181 additions and 133 deletions

View file

@ -61,6 +61,7 @@ struct iop {
struct ioqueue *output;
int flags;
int bufsize;
struct timeval input_timeout;
};
void
@ -69,7 +70,7 @@ io_init(void)
}
struct iop *
io_open(int fd, int flags, int bufsize)
io_open(int fd, int flags, int bufsize, struct timeval timeout)
{
struct iop *iop;
@ -83,6 +84,7 @@ io_open(int fd, int flags, int bufsize)
iop->input = 0;
iop->output = 0;
iop->flags = 0;
iop->input_timeout = timeout;
iop->bufsize = bufsize;
if ((flags & IO_READ) && (flags & IO_NEWSOCK) == 0)
iop->input = ioq_create(bufsize);
@ -106,31 +108,47 @@ io_close(struct iop *iop)
free(iop);
}
/*
* Return number of bytes read on success, zero on timeout or EOF, -1
* on error, with errno set appropriately. In particular, return -1
* with errno set to EAGAIN or EWOULDBLOCK when no data is available
* for non-blocking input (WAITFORINPUT false). Use io_eof() to
* distinguish timeout from EOF.
*/
int
io_input(struct iop *iop, int waitforinput)
{
char buf[IO_BUFSIZE];
int cc;
int res;
struct timeval timeout = iop->input_timeout;
/* Not a read IOP */
if ((iop->flags & IO_READ) == 0)
if ((iop->flags & IO_READ) == 0) {
errno = EBADF;
return -1;
}
/* IOP is markes as in error. */
if (iop->flags & IO_ERROR)
if (iop->flags & IO_ERROR) {
errno = EBADF;
return -1;
}
/* Wait for the file to have input. */
if (waitforinput) {
empth_select(iop->fd, EMPTH_FD_READ);
res = empth_select(iop->fd, EMPTH_FD_READ, &timeout);
if (res < 0) {
iop->flags |= IO_ERROR;
return -1;
} else if (res == 0)
return 0;
}
/* Do the actual read. */
cc = read(iop->fd, buf, sizeof(buf));
if (cc < 0) {
/* would block, so nothing to read. */
if (errno == EAGAIN || errno == EWOULDBLOCK)
return 0;
/* Some form of file error occurred... */
iop->flags |= IO_ERROR;
if (errno != EAGAIN && errno != EWOULDBLOCK)
/* Some form of file error occurred... */
iop->flags |= IO_ERROR;
return -1;
}
@ -190,7 +208,7 @@ io_output(struct iop *iop, int waitforoutput)
if (waitforoutput != IO_NOWAIT) {
/* This waits for the file to be ready for writing, */
/* and lets other threads run. */
empth_select(iop->fd, EMPTH_FD_WRITE);
empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
}
/* Do the actual write. */
@ -272,7 +290,7 @@ io_output_all(struct iop *iop)
* a malicous player could delay the update indefinitely
*/
while ((n = io_output(iop, IO_NOWAIT)) > 0 && !play_wrlock_wanted)
empth_select(iop->fd, EMPTH_FD_WRITE);
empth_select(iop->fd, EMPTH_FD_WRITE, NULL);
return n;
}

View file

@ -104,10 +104,10 @@ empth_terminate(empth_t *a)
lwpTerminate(a);
}
void
empth_select(int fd, int flags)
int
empth_select(int fd, int flags, struct timeval *timeout)
{
lwpSleepFd(fd, flags);
return lwpSleepFd(fd, flags, timeout);
}
void

View file

@ -560,12 +560,14 @@ empth_terminate(empth_t *pThread)
*
* This would be one of the main functions used within gen\io.c
*/
void
empth_select(int fd, int flags)
int
empth_select(int fd, int flags, struct timeval *timeout)
{
int handle;
WSAEVENT hEventObject[2];
DWORD result, msec;
empth_t *pThread = TlsGetValue(dwTLSIndex);
int res;
loc_debug("%s select on %d",
flags == EMPTH_FD_READ ? "read" : "write", fd);
@ -586,13 +588,31 @@ empth_select(int fd, int flags)
empth_exit();
}
WSAWaitForMultipleEvents(2, hEventObject, FALSE, WSA_INFINITE, FALSE);
if (timeout)
msec = timeout->tv_sec * 1000L + timeout->tv_usec / 1000L;
else
msec = WSA_INFINITE;
result = WSAWaitForMultipleEvents(2, hEventObject, FALSE, msec,
FALSE);
switch (result) {
case WSA_WAIT_TIMEOUT:
res = 0;
break;
case WSA_WAIT_FAILED:
errno = WSAGetLastError();
res = -1;
break;
default:
res = 1;
}
WSAEventSelect(handle, hEventObject[0], 0);
WSACloseEvent(hEventObject[0]);
loc_RunThisThread(NULL);
return res;
}
/************************

View file

@ -289,65 +289,58 @@ empth_terminate(empth_t *a)
pthread_kill(a->id, SIGALRM);
}
void
empth_select(int fd, int flags)
int
empth_select(int fd, int flags, struct timeval *tv)
{
fd_set readmask;
fd_set writemask;
struct timeval tv;
int n;
int res = 0;
pthread_mutex_unlock(&mtx_ctxsw);
empth_status("%s select on %d",
flags == EMPTH_FD_READ ? "read" : "write", fd);
while (1) {
tv.tv_sec = 1000000;
tv.tv_usec = 0;
FD_ZERO(&readmask);
FD_ZERO(&writemask);
FD_ZERO(&readmask);
FD_ZERO(&writemask);
switch (flags) {
case EMPTH_FD_READ:
FD_SET(fd, &readmask);
break;
case EMPTH_FD_WRITE:
FD_SET(fd, &writemask);
break;
default:
logerror("bad flag %d passed to empth_select", flags);
empth_exit();
}
n = select(fd + 1, &readmask, &writemask, (fd_set *) 0, &tv);
if (n < 0) {
if (errno == EINTR) {
/* go handle the signal */
empth_status("select broken by signal");
goto done;
return;
}
/* strange but we dont get EINTR on select broken by signal */
empth_status("select failed (%s)", strerror(errno));
goto done;
return;
}
if (flags == EMPTH_FD_READ && FD_ISSET(fd, &readmask)) {
empth_status("input ready");
break;
}
if (flags == EMPTH_FD_WRITE && FD_ISSET(fd, &writemask)) {
empth_status("output ready");
break;
}
switch (flags) {
case EMPTH_FD_READ:
FD_SET(fd, &readmask);
break;
case EMPTH_FD_WRITE:
FD_SET(fd, &writemask);
break;
default:
CANT_REACH();
errno = EINVAL;
res = -1;
goto done;
}
done:
n = select(fd + 1, &readmask, &writemask, (fd_set *) 0, tv);
if (n < 0) {
if (errno == EINTR) /* go handle the signal */
empth_status("select broken by signal");
else
empth_status("select failed (%s)", strerror(errno));
res = -1;
} else if (n == 0) {
empth_status("select timed out");
res = 0;
} else if (flags == EMPTH_FD_READ && FD_ISSET(fd, &readmask)) {
empth_status("input ready");
res = 1;
} else if (flags == EMPTH_FD_WRITE && FD_ISSET(fd, &writemask)) {
empth_status("output ready");
res = 1;
}
done:
pthread_mutex_lock(&mtx_ctxsw);
empth_restorectx();
return res;
}
static void