@@ -57,7 +57,115 @@ static int read(SOCKET s, char *buf, size_t count) {
5757 }
5858 return (int )count_received ;
5959}
60- #define poll WSAPoll
60+
61+ // WSAPoll doesn't exist on Windows before Vista, and isn't reliable before some version of Windows 10,
62+ // so for now we just fake it with select().
63+ static int WindowsPoll (struct pollfd * fds , unsigned int nfds , int timeout )
64+ {
65+ SDL_assert (fds != NULL );
66+ SDL_assert (nfds > 0 );
67+
68+ int nreadfds = 0 , nwritefds = 0 , nexceptfds = nfds ;
69+ for (unsigned int i = 0 ; i < nfds ; i ++ ) {
70+ fds [i ].revents = 0 ;
71+ if (fds [i ].events & POLLIN ) {
72+ nreadfds ++ ;
73+ }
74+ if (fds [i ].events & POLLOUT ) {
75+ nwritefds ++ ;
76+ }
77+ }
78+
79+ // FD_SETSIZE is 64 on Windows, but they don't use bitsets, so you can
80+ // just supply your own struct that uses any length.
81+ //
82+ // https://devblogs.microsoft.com/oldnewthing/20221102-00/?p=107343
83+ typedef struct WindowsPoll_fd_set {
84+ Uint32 count ;
85+ SOCKET sockets []; // variable-length array
86+ } WindowsPoll_fd_set ;
87+
88+ Uint8 stackbuf_read [256 ]; // in case if we can do this without malloc.
89+ Uint8 stackbuf_write [256 ]; // in case if we can do this without malloc.
90+ Uint8 stackbuf_except [256 ]; // in case if we can do this without malloc.
91+ WindowsPoll_fd_set * readfds = NULL ;
92+ WindowsPoll_fd_set * writefds = NULL ;
93+ WindowsPoll_fd_set * exceptfds = NULL ;
94+
95+ bool failed = false;
96+ #define ALLOC_FDSET (typ ) { \
97+ if (!failed && (n##typ##fds > 0)) { \
98+ const int len = sizeof (Uint32) + (n##typ##fds * sizeof (SOCKET)); \
99+ if (len < sizeof (stackbuf_##typ)) { \
100+ typ##fds = (WindowsPoll_fd_set *) stackbuf_##typ; \
101+ } else { \
102+ typ##fds = (WindowsPoll_fd_set *) SDL_malloc(len); \
103+ if (!typ##fds) { \
104+ failed = true; \
105+ } \
106+ } \
107+ if (typ##fds) { \
108+ SDL_memset(typ##fds, '\0', len); \
109+ } \
110+ } \
111+ }
112+ ALLOC_FDSET (read );
113+ ALLOC_FDSET (write );
114+ ALLOC_FDSET (except );
115+ #undef ALLOC_FDSET
116+
117+ int retval = -1 ;
118+ if (!failed ) {
119+ for (unsigned int i = 0 ; i < nfds ; i ++ ) {
120+ exceptfds -> sockets [exceptfds -> count ++ ] = fds [i ].fd ;
121+ if (fds [i ].events & POLLIN ) {
122+ readfds -> sockets [readfds -> count ++ ] = fds [i ].fd ;
123+ }
124+ if (fds [i ].events & POLLOUT ) {
125+ writefds -> sockets [writefds -> count ++ ] = fds [i ].fd ;
126+ }
127+ }
128+
129+ struct timeval tvtimeout ;
130+ struct timeval * ptvtimeout = NULL ;
131+
132+ if (timeout >= 0 ) {
133+ tvtimeout .tv_sec = timeout / 1000 ;
134+ tvtimeout .tv_usec = (timeout % 1000 ) * 1000 ;
135+ ptvtimeout = & tvtimeout ;
136+ }
137+
138+ // WinSock's select() ignores the first parameter, since it doesn't use bitsets, and SOCKETs aren't small integers. Just specify zero here.
139+ retval = select (0 , (fd_set * ) readfds , (fd_set * ) writefds , (fd_set * ) exceptfds , ptvtimeout );
140+ if (retval > 0 ) {
141+ #define CHECKSET (typ , flag ) { \
142+ if (typ##fds != NULL) { \
143+ for (Uint32 i = 0; i < typ##fds->count; i++) { \
144+ SOCKET sock = typ##fds->sockets[i]; \
145+ for (unsigned int j = 0; j < nfds; j++) { \
146+ if (fds[j].fd == sock) { \
147+ fds[j].revents |= flag; \
148+ } \
149+ } \
150+ } \
151+ } \
152+ }
153+ CHECKSET (read , POLLIN );
154+ CHECKSET (write , POLLOUT );
155+ CHECKSET (except , POLLERR );
156+ #undef CHECKSET
157+ }
158+ }
159+
160+ if ((void * ) readfds != (void * ) stackbuf_read ) { SDL_free (readfds ); }
161+ if ((void * ) writefds != (void * ) stackbuf_write ) { SDL_free (writefds ); }
162+ if ((void * ) exceptfds != (void * ) stackbuf_except ) { SDL_free (exceptfds ); }
163+
164+ return retval ;
165+ }
166+
167+ #define poll WindowsPoll
168+
61169#else
62170#include <sys/types.h>
63171#include <sys/socket.h>
@@ -1950,6 +2058,7 @@ int NET_WaitUntilInputAvailable(void **vsockets, int numsockets, int timeoutms)
19502058 return SetLastSocketError ("Socket poll failed" );
19512059 }
19522060
2061+ // !!! FIXME: skip this loop if rc == 0.
19532062 pfd = & pfds [0 ];
19542063 for (int i = 0 ; i < numsockets ; i ++ ) {
19552064 NET_GenericSocket * sock = sockets [i ];
0 commit comments