Skip to content

Commit cd09a2a

Browse files
committed
Expose poll() to wait on single fds
1 parent 13643f9 commit cd09a2a

File tree

8 files changed

+96
-11
lines changed

8 files changed

+96
-11
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import com.oracle.graal.python.builtins.CoreFunctions;
6868
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
6969
import com.oracle.graal.python.builtins.PythonBuiltins;
70+
import com.oracle.graal.python.builtins.PythonOS;
7071
import com.oracle.graal.python.builtins.modules.SysModuleBuiltins;
7172
import com.oracle.graal.python.builtins.objects.PNone;
7273
import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary;
@@ -137,7 +138,9 @@ private static void checkSelectable(Node inliningTarget, PRaiseNode raiseNode, P
137138
}
138139

139140
private static boolean isSelectable(PSocket socket) {
140-
return socket.getTimeoutNs() <= 0 || socket.getFd() < PosixConstants.FD_SETSIZE.value;
141+
// See posix.c - on Unix systems we use poll() instead of select() which does not have the
142+
// limitation of select()
143+
return PythonOS.getPythonOS() != PythonOS.PLATFORM_WIN32 || socket.getTimeoutNs() <= 0 || socket.getFd() < PosixConstants.FD_SETSIZE.value;
141144
}
142145

143146
// socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -44,14 +44,12 @@
4444
import static com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.EINTR;
4545
import static com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.EWOULDBLOCK;
4646
import static com.oracle.graal.python.builtins.objects.socket.PSocket.INVALID_FD;
47-
import static com.oracle.graal.python.util.PythonUtils.EMPTY_INT_ARRAY;
4847

4948
import com.oracle.graal.python.nodes.ErrorMessages;
5049
import com.oracle.graal.python.nodes.PConstructAndRaiseNode;
5150
import com.oracle.graal.python.runtime.GilNode;
5251
import com.oracle.graal.python.runtime.PosixSupportLibrary;
5352
import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException;
54-
import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult;
5553
import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval;
5654
import com.oracle.graal.python.runtime.PythonContext;
5755
import com.oracle.graal.python.util.TimeUtils;
@@ -101,12 +99,9 @@ public static <T> T callSocketFunctionWithRetry(Frame frame, Node inliningTarget
10199
try {
102100
gil.release(true);
103101
try {
104-
int[] fds = new int[]{socket.getFd()};
105-
int[] readfds = writing ? EMPTY_INT_ARRAY : fds;
106-
int[] writefds = writing ? fds : EMPTY_INT_ARRAY;
107-
SelectResult selectResult = posixLib.select(posixSupport, readfds, writefds, EMPTY_INT_ARRAY, selectTimeout);
108-
boolean[] resultFds = writing ? selectResult.getWriteFds() : selectResult.getReadFds();
109-
if (resultFds.length == 0 || !resultFds[0]) {
102+
// CPython uses poll for a single fd when available here, so even higher fd
103+
// socket connections can be established
104+
if (!posixLib.poll(posixSupport, socket.getFd(), writing, selectTimeout)) {
110105
throw constructAndRaiseNode.get(inliningTarget).raiseTimeoutError(frame, ErrorMessages.TIMED_OUT);
111106
}
112107
} finally {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
import static com.oracle.graal.python.runtime.PosixConstants.TCP_NODELAY;
128128
import static com.oracle.graal.python.runtime.PosixConstants.W_OK;
129129
import static com.oracle.graal.python.runtime.PosixConstants.X_OK;
130+
import static com.oracle.graal.python.util.PythonUtils.EMPTY_INT_ARRAY;
130131
import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
131132
import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached;
132133
import static com.oracle.graal.python.util.PythonUtils.tsLiteral;
@@ -726,6 +727,17 @@ private SelectableChannel[] getSelectableChannels(int[] fds) throws PosixExcepti
726727
return channels;
727728
}
728729

730+
@ExportMessage
731+
public boolean poll(int fd, boolean forWriting, Timeval timeout) throws PosixException {
732+
SelectResult r = select(forWriting ? EMPTY_INT_ARRAY : new int[]{fd},
733+
forWriting ? new int[]{fd} : EMPTY_INT_ARRAY, EMPTY_INT_ARRAY, timeout);
734+
if (forWriting) {
735+
return r.getWriteFds().length > 0 && r.getWriteFds()[0];
736+
} else {
737+
return r.getReadFds().length > 0 && r.getReadFds()[0];
738+
}
739+
}
740+
729741
@ExportMessage
730742
public long lseek(int fd, long offset, int how,
731743
@Bind("$node") Node inliningTarget,

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,17 @@ public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeva
262262
}
263263
}
264264

265+
@ExportMessage
266+
public boolean poll(int fd, boolean forWriting, Timeval timeout,
267+
@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException {
268+
logEnter("poll", "%s %s %s", fd, forWriting, timeout);
269+
try {
270+
return logExit("poll", "%s", lib.poll(delegate, fd, forWriting, timeout));
271+
} catch (PosixException e) {
272+
throw logException("poll", e);
273+
}
274+
}
275+
265276
@ExportMessage
266277
final long lseek(int fd, long offset, int how,
267278
@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NFIPosixSupport.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ private enum PosixNativeFunction {
185185
call_dup2("(sint32, sint32, sint32):sint32"),
186186
call_pipe2("([sint32]):sint32"),
187187
call_select("(sint32, [sint32], sint32, [sint32], sint32, [sint32], sint32, sint64, sint64, [sint8]):sint32"),
188+
call_poll("(sint32, sint32, sint64, sint64):sint32"),
188189
call_lseek("(sint32, sint64, sint32):sint64"),
189190
call_ftruncate("(sint32, sint64):sint32"),
190191
call_truncate("([sint8], sint64):sint32"),
@@ -669,6 +670,26 @@ private static int findMax(int[] items, int currentMax) {
669670
return max;
670671
}
671672

673+
@ExportMessage
674+
public boolean poll(int fd, boolean forWriting, Timeval timeout,
675+
@Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException {
676+
long secs = -1, usecs = -1;
677+
if (timeout != null) {
678+
secs = timeout.getSeconds();
679+
usecs = timeout.getMicroseconds();
680+
}
681+
int result = invokeNode.callInt(this, PosixNativeFunction.call_poll, fd,
682+
forWriting ? 1 : 0, secs, usecs);
683+
if (result < 0) {
684+
throw getErrnoAndThrowPosixException(invokeNode);
685+
}
686+
if (result == 0) {
687+
return false;
688+
} else {
689+
return true;
690+
}
691+
}
692+
672693
@ExportMessage
673694
public long lseek(int fd, long offset, int how,
674695
@Shared("invoke") @Cached InvokeNativeFunction invokeNode) throws PosixException {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ public abstract class PosixSupportLibrary extends Library {
107107

108108
public abstract SelectResult select(Object receiver, int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException;
109109

110+
public abstract boolean poll(Object receiver, int fd, boolean forWriting, Timeval timeout) throws PosixException;
111+
110112
public abstract long lseek(Object receiver, int fd, long offset, int how) throws PosixException;
111113

112114
public abstract void ftruncate(Object receiver, int fd, long length) throws PosixException;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval
254254
return nativeLib.select(nativePosixSupport, readfds, writefds, errorfds, timeout);
255255
}
256256

257+
@ExportMessage
258+
final boolean poll(int fd, boolean forWriting, Timeval timeout,
259+
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException {
260+
checkNotInPreInitialization();
261+
return nativeLib.poll(nativePosixSupport, fd, forWriting, timeout);
262+
}
263+
257264
@ExportMessage
258265
final long lseek(int fd, long offset, int how,
259266
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException {

graalpython/python-libposix/src/posix.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@
8484
#endif
8585

8686
#ifndef _WIN32
87+
#include <time.h>
88+
#include <poll.h>
89+
#include <limits.h>
8790
#include <sys/resource.h>
8891
#endif
8992

@@ -198,7 +201,6 @@ static void fill_fd_set(fd_set *set, int32_t* fds, int32_t len) {
198201
int32_t call_select(int32_t nfds, int32_t* readfds, int32_t readfdsLen,
199202
int32_t* writefds, int32_t writefdsLen, int32_t* errfds, int32_t errfdsLen,
200203
int64_t timeoutSec, int64_t timeoutUsec, int8_t* selected) {
201-
202204
fd_set readfdsSet, writefdsSet, errfdsSet;
203205
fill_fd_set(&readfdsSet, readfds, readfdsLen);
204206
fill_fd_set(&writefdsSet, writefds, writefdsLen);
@@ -215,6 +217,38 @@ int32_t call_select(int32_t nfds, int32_t* readfds, int32_t readfdsLen,
215217
return (int32_t) result;
216218
}
217219

220+
int32_t call_poll(int32_t fd, int32_t writing, int64_t timeoutSec, int64_t timeoutUsec) {
221+
#ifdef _WIN32
222+
// for windows, use select() as a worse fallback
223+
int selected[2] = {0, 0};
224+
return call_select(1,
225+
writing ? NULL : &fd, writing ? 0 : 1,
226+
writing ? &fd : NULL, writing ? 1 : 0,
227+
NULL, 0,
228+
timeoutSec, timeoutUsec, &selected);
229+
#else
230+
struct pollfd pollfd;
231+
pollfd.fd = fd;
232+
pollfd.events = writing ? POLLOUT : POLLIN;
233+
234+
int timeout_ms;
235+
if (timeoutSec < 0) {
236+
timeout_ms = -1;
237+
} else if (timeoutSec > INT_MAX / 1000) {
238+
errno = EINVAL;
239+
return -1;
240+
} else {
241+
int64_t timeout_ms_64 = timeoutSec * 1000 + timeoutUsec / 1000;
242+
if (timeout_ms_64 > INT_MAX) {
243+
errno = EINVAL;
244+
return -1;
245+
}
246+
timeout_ms = (int)timeout_ms_64;
247+
}
248+
return poll(&pollfd, 1, timeout_ms);
249+
#endif
250+
}
251+
218252
int64_t call_lseek(int32_t fd, int64_t offset, int32_t whence) {
219253
return lseek(fd, offset, whence);
220254
}

0 commit comments

Comments
 (0)