#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <io.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <emx/io.h>
#define I_NEED_OS2_H
#define INCL_DOSSEMAPHORES
#define INCL_DOSPROFILE
#define INCL_DOSPROCESS
#define INCL_DOSFILEMGR
#define INCL_DOSMISC
#define INCL_DOSMODULEMGR
#include "Xpoll.h"
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86_OSlib.h"
#include "os2_select.h"
int os2MouseQueueQuery();
int os2KbdQueueQuery();
void os2RecoverFromPopup();
void os2CheckPopupPending();
void os2SocketMonitorThread();
extern BOOL os2PopupErrorPending;
extern HEV hKbdSem;
extern HEV hMouseSem;
extern HEV hevServerHasFocus;
HEV hPipeSem;
HEV hSocketSem;
HEV hActivateSocketSem;
HEV hSwitchToSem;
static HMUX hSelectWait;
SEMRECORD SelectMuxRecord[5];
HMODULE hmod_so32dll;
static struct select_data sd;
static int (*os2_tcp_select)(int *,int,int,int,long);
static int (*os2_so_cancel)(int);
static int (*os2_sock_errno)();
int os2_set_error(ULONG);
extern int _files[];
int os2PseudoSelect(nfds,readfds,writefds,exceptfds,timeout)
int nfds;
fd_set *readfds,*writefds,*exceptfds;
struct timeval *timeout;
{
static BOOL FirstTime=TRUE;
int n,ns,np;
int ready_handles;
ULONG timeout_ms;
BOOL any_ready;
ULONG semKey,postCount;
APIRET rc;
char faildata[16];
static int Socket_Tid;
sd.have_read=FALSE; sd.have_write=FALSE;
sd.socket_nread=0; sd.socket_nwrite=0; sd.socket_ntotal=0;
sd.max_fds=31; ready_handles=0; any_ready=FALSE;
sd.pipe_ntotal=0; sd.pipe_have_write=FALSE;
if (FirstTime) {
if ((rc=DosLoadModule(faildata,sizeof(faildata),"SO32DLL",&hmod_so32dll))!=0) {
FatalError("Could not load module so32dll.dll, rc = %d. Error note %s\n",rc,faildata);
}
if ((rc = DosQueryProcAddr(hmod_so32dll, 0, "SELECT", (PPFN)&os2_tcp_select))!=0) {
FatalError("Could not query address of SELECT, rc = %d.\n",rc);
}
if ((rc = DosQueryProcAddr(hmod_so32dll, 0, "SO_CANCEL", (PPFN)&os2_so_cancel))!=0) {
FatalError("Could not query address of SO_CANCEL, rc = %d.\n",rc);
}
if ((rc = DosQueryProcAddr(hmod_so32dll, 0, "SOCK_ERRNO", (PPFN)&os2_sock_errno))!=0) {
FatalError("Could not query address of SOCK_ERRNO, rc = %d.\n",rc);
}
xf86OsMouseEvents();
xf86KbdEvents();
DosCreateEventSem(NULL, &hSocketSem,DC_SEM_SHARED,FALSE);
DosResetEventSem(hSocketSem,&postCount);
DosCreateEventSem(NULL, &hActivateSocketSem, DC_SEM_SHARED, FALSE);
DosResetEventSem(hActivateSocketSem, &postCount);
DosCreateEventSem(NULL, &hSwitchToSem, DC_SEM_SHARED, FALSE);
DosResetEventSem(hSwitchToSem, &postCount);
Socket_Tid = _beginthread(os2SocketMonitorThread, NULL, 0x2000,(void *) NULL);
xf86Msg(X_INFO,
"Started Socket monitor thread, TID=%d\n",Socket_Tid);
SelectMuxRecord[0].hsemCur = (HSEM)hMouseSem;
SelectMuxRecord[0].ulUser = MOUSE_SEM_KEY;
SelectMuxRecord[1].hsemCur = (HSEM)hKbdSem;
SelectMuxRecord[1].ulUser = KBD_SEM_KEY;
SelectMuxRecord[2].hsemCur = (HSEM)hPipeSem;
SelectMuxRecord[2].ulUser = PIPE_SEM_KEY;
SelectMuxRecord[3].hsemCur = (HSEM)hSocketSem;
SelectMuxRecord[3].ulUser = SOCKET_SEM_KEY;
SelectMuxRecord[4].hsemCur = (HSEM)hSwitchToSem;
SelectMuxRecord[4].ulUser = SWITCHTO_SEM_KEY;
rc = DosCreateMuxWaitSem(NULL, &hSelectWait, 5, SelectMuxRecord,
DC_SEM_SHARED | DCMW_WAIT_ANY);
if (rc) {
xf86Msg(X_ERROR,"Could not create MuxWait semaphore, rc=%d\n",rc);
}
FirstTime = FALSE;
}
rc = DosResetEventSem(hActivateSocketSem, &postCount);
if (timeout!=NULL) {
timeout_ms=timeout->tv_sec*1000+timeout->tv_usec/1000;
} else {
timeout_ms=1000000;
}
{FD_ZERO(&sd.read_copy);}
{FD_ZERO(&sd.write_copy);}
if (readfds!=NULL) { XFD_COPYSET(readfds,&sd.read_copy); sd.have_read=TRUE; }
if (writefds!=NULL) {XFD_COPYSET(writefds,&sd.write_copy); sd.have_write=TRUE; }
if (sd.have_read){ FD_ZERO(readfds); }
if (sd.have_write) {FD_ZERO(writefds); }
if (exceptfds != NULL) {FD_ZERO(exceptfds); }
n = os2_parse_select(&sd,nfds);
if (sd.socket_ntotal > 0) {
ns = os2_poll_sockets(&sd,readfds,writefds);
if (ns>0) {
ready_handles+=ns;
any_ready = TRUE;
} else if (ns == -1) {
return(-1);
}
}
if (sd.pipe_ntotal > 0) {
np = os2_check_pipes(&sd,readfds,writefds);
if (np > 0) {
ready_handles+=np;
any_ready = TRUE;
} else if (np == -1) {
return(-1);
}
}
if(!os2MouseQueueQuery() || !os2KbdQueueQuery() ) any_ready = TRUE;
if (xf86Info.vtRequestsPending) any_ready=TRUE;
if (os2PopupErrorPending)
os2RecoverFromPopup();
if (!any_ready && timeout_ms) {
DosResetEventSem(hSocketSem,&postCount);
if (sd.socket_ntotal>0) {
rc = DosPostEventSem(hActivateSocketSem);
}
rc = DosWaitMuxWaitSem(hSelectWait, timeout_ms, &semKey);
if (sd.socket_ntotal>0) {
rc = DosQueryEventSem(hSocketSem, &postCount);
if (postCount == 0) {
int i,f,g;
struct select_data *sd_ptr=&sd;
if (sd.socket_nread > 0) {
for (i=0; i<sd.socket_nread; i++) {
f = g = sd_ptr->tcp_select_mask[i];
os2_so_cancel(f);
os2_tcp_select(&g, 1, 0, 0, 0);
}
}
if (sd.socket_nwrite > 0) {
for (i=sd.socket_nread;
i<sd.socket_nread+sd.socket_nwrite;
i++) {
f = g = sd_ptr->tcp_select_mask[i];
os2_so_cancel(f);
os2_tcp_select(&g, 0, 1, 0, 0);
}
}
} else {
ns = os2_poll_sockets(&sd,readfds,writefds);
if (ns>0) {
ready_handles+=ns;
} else if (ns == -1) {
return(-1);
}
}
}
if (sd.pipe_ntotal > 0) {
rc = DosQueryEventSem(hPipeSem,&postCount);
if (postCount > 0) {
np = os2_check_pipes(&sd,readfds,writefds);
if (np > 0) {
ready_handles+=np;
} else if (np == -1) {
return(-1);
}
}
}
}
return (ready_handles);
}
int os2_parse_select(sd,nfds)
struct select_data *sd;
int nfds;
{
int i;
if (nfds > sd->max_fds) {
for (i=0;i<((FD_SETSIZE+31)/32);i++) {
if (sd->read_copy.fds_bits[i] ||
sd->write_copy.fds_bits[i])
sd->max_fds=(i*32) +32;
}
} else { sd->max_fds = nfds; }
if(sd->max_fds > nfds) sd->max_fds = nfds;
if (sd->have_read) {
for (i = 0; i < sd->max_fds; ++i) {
if (FD_ISSET (i, &sd->read_copy)) {
if(_files[i] & F_SOCKET) {
sd->tcp_select_mask[sd->socket_ntotal]=_getsockhandle(i);
sd->tcp_emx_handles[sd->socket_ntotal]=i;
sd->socket_ntotal++; sd->socket_nread++;
} else if (_files[i] & F_PIPE) {
sd -> pipe_ntotal++;
}
}
}
}
if (sd->have_write) {
for (i = 0; i < sd->max_fds; ++i) {
if (FD_ISSET (i, &sd->write_copy)) {
if (_files[i] & F_SOCKET) {
sd->tcp_select_mask[sd->socket_ntotal]=_getsockhandle(i);
sd->tcp_emx_handles[sd->socket_ntotal]=i;
sd->socket_ntotal++; sd->socket_nwrite++;
} else if (_files[i] & F_PIPE) {
sd -> pipe_ntotal++;
sd -> pipe_have_write=TRUE;
}
}
}
}
return(sd->socket_ntotal);
}
int os2_poll_sockets(sd,readfds,writefds)
struct select_data *sd;
fd_set *readfds,*writefds;
{
int e,i;
int j,n;
memcpy(sd->tcp_select_copy,sd->tcp_select_mask,
sd->socket_ntotal*sizeof(int));
e = os2_tcp_select(sd->tcp_select_copy,sd->socket_nread,
sd->socket_nwrite, 0, 0);
if (e == 0) return(e);
if (e>0) {
j = 0; n = 0;
for (i = 0; i < sd->socket_nread; ++i, ++j)
if (sd->tcp_select_copy[j] != -1) {
FD_SET (sd->tcp_emx_handles[j], readfds);
n ++;
}
for (i = 0; i < sd->socket_nwrite; ++i, ++j)
if (sd->tcp_select_copy[j] != -1) {
FD_SET (sd->tcp_emx_handles[j], writefds);
n ++;
}
errno = 0;
return n;
}
if (e<0) {
xf86Msg(X_ERROR,"Error in server select! sock_errno = %d\n",os2_sock_errno());
errno = EBADF;
return (-1);
}
}
int os2_check_pipes(sd,readfds,writefds)
struct select_data *sd;
fd_set *readfds,*writefds;
{
int i,e;
ULONG ulPostCount;
PIPESEMSTATE pipeSemState[128];
APIRET rc;
e = 0;
rc = DosResetEventSem(hPipeSem,&ulPostCount);
rc = DosQueryNPipeSemState((HSEM) hPipeSem, (PPIPESEMSTATE)&pipeSemState,
sizeof(pipeSemState));
if(rc) xf86Msg(X_ERROR,"SELECT: rc from QueryNPipeSem: %d\n",rc);
i=0;
while (pipeSemState[i].fStatus != 0) {
if ((pipeSemState[i].fStatus == 1) &&
(FD_ISSET(pipeSemState[i].usKey,&sd->read_copy))) {
FD_SET(pipeSemState[i].usKey,readfds);
e++;
} else if ((pipeSemState[i].fStatus == 2) &&
(FD_ISSET(pipeSemState[i].usKey,&sd->write_copy))) {
FD_SET(pipeSemState[i].usKey,writefds);
e++;
} else if ((pipeSemState[i].fStatus == 3) &&
((FD_ISSET(pipeSemState[i].usKey,&sd->read_copy)) ||
(FD_ISSET(pipeSemState[i].usKey,&sd->write_copy)) )) {
errno = EBADF;
return (-1);
}
i++;
}
errno = 0;
return(e);
}
void os2SocketMonitorThread(void *arg)
{
struct select_data *sd_ptr = &sd;
ULONG ulPostCount;
int e,rc;
DosSetPriority(2L,3L,0L,0L);
while (1) {
rc = DosWaitEventSem(hActivateSocketSem, SEM_INDEFINITE_WAIT);
if (rc != 0 )
xf86Msg(X_ERROR,"Socket monitor: DosWaitEventSem(hActivateSocketSem..) returned %d\n",rc);
rc = DosResetEventSem(hActivateSocketSem,&ulPostCount);
if (rc != 0 )
xf86Msg(X_ERROR,"Socket monitor: DosResetEventSem(&hActivateSocketSem..) returned %d\n",rc);
memcpy(sd_ptr->tcp_select_monitor,sd_ptr->tcp_select_mask,
sd_ptr->socket_ntotal*sizeof(int));
e = os2_tcp_select(sd_ptr->tcp_select_monitor, sd_ptr->socket_nread,
sd_ptr->socket_nwrite, 0, -1);
if (e>0) {
rc = DosPostEventSem(hSocketSem);
if (rc != 0 )
xf86Msg(X_ERROR,"Socket monitor: DosPostEventSem(hSocketSem..) returned %d\n",rc);
} else if (e<0) {
rc = os2_sock_errno();
if (rc != 10004)
xf86Msg(X_ERROR,"Socket monitor: os2_select: sock_errno = %d\n",rc);
}
rc = DosQueryEventSem(hevServerHasFocus, &ulPostCount);
if ((rc==0) && (ulPostCount==0))
rc == DosWaitEventSem(hevServerHasFocus,31L);
}
}