Skip to content

Commit db9d1f6

Browse files
committed
Use emulated select() when sockets are involved
1 parent 65dd7b4 commit db9d1f6

File tree

6 files changed

+83
-21
lines changed

6 files changed

+83
-21
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
6464
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
6565
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
66+
import com.oracle.graal.python.runtime.EmulatedPosixSupport;
67+
import com.oracle.graal.python.runtime.PosixResources;
6668
import com.oracle.graal.python.runtime.PosixSupportLibrary;
6769
import com.oracle.graal.python.runtime.PosixSupportLibrary.ChannelNotSelectableException;
6870
import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException;
@@ -126,10 +128,10 @@ PTuple doGeneric(VirtualFrame frame, Object rlist, Object wlist, Object xlist, O
126128
@Cached PyTimeFromObjectNode pyTimeFromObjectNode,
127129
@CachedLibrary(limit = "3") PythonObjectLibrary itemLib,
128130
@Cached BranchProfile notSelectableBranch) {
129-
130-
ObjAndFDList readFDs = seq2set(frame, rlist, rlistLibrary, itemLib, callGetItemNode, constructListNode);
131-
ObjAndFDList writeFDs = seq2set(frame, wlist, wlistLibrary, itemLib, callGetItemNode, constructListNode);
132-
ObjAndFDList xFDs = seq2set(frame, xlist, xlistLibrary, itemLib, callGetItemNode, constructListNode);
131+
EmulatedPosixSupport emulatedPosixSupport = getContext().getResources();
132+
ObjAndFDList readFDs = seq2set(frame, rlist, rlistLibrary, itemLib, callGetItemNode, constructListNode, emulatedPosixSupport);
133+
ObjAndFDList writeFDs = seq2set(frame, wlist, wlistLibrary, itemLib, callGetItemNode, constructListNode, emulatedPosixSupport);
134+
ObjAndFDList xFDs = seq2set(frame, xlist, xlistLibrary, itemLib, callGetItemNode, constructListNode, emulatedPosixSupport);
133135

134136
Timeval timeoutval = null;
135137
if (!PGuards.isPNone(timeout)) {
@@ -141,7 +143,12 @@ PTuple doGeneric(VirtualFrame frame, Object rlist, Object wlist, Object xlist, O
141143

142144
SelectResult result;
143145
try {
144-
result = posixLib.select(getPosixSupport(), readFDs.fds, writeFDs.fds, xFDs.fds, timeoutval);
146+
if (readFDs.containsSocket || writeFDs.containsSocket || xFDs.containsSocket) {
147+
// TODO remove this once native sockets are supported
148+
result = PosixSupportLibrary.getUncached().select(emulatedPosixSupport, readFDs.fds, writeFDs.fds, xFDs.fds, timeoutval);
149+
} else {
150+
result = posixLib.select(getPosixSupport(), readFDs.fds, writeFDs.fds, xFDs.fds, timeoutval);
151+
}
145152
} catch (PosixException e) {
146153
throw raiseOSErrorFromPosixException(frame, e);
147154
} catch (ChannelNotSelectableException e) {
@@ -171,30 +178,35 @@ private PList toList(boolean[] result, ObjAndFDList fds) {
171178
}
172179

173180
private static ObjAndFDList seq2set(VirtualFrame frame, Object sequence, PythonObjectLibrary sequenceLib, PythonObjectLibrary itemLib, LookupAndCallBinaryNode callGetItemNode,
174-
FastConstructListNode constructListNode) {
181+
FastConstructListNode constructListNode, PosixResources resources) {
175182
PArguments.ThreadState threadState = PArguments.getThreadState(frame);
176183
// We cannot assume any size of those two arrays, because the sequence may change as a
177184
// side effect of the invocation of fileno. We also need to call lengthWithState
178185
// repeatedly in the loop condition
179186
ArrayBuilder<Object> objects = new ArrayBuilder<>();
180187
IntArrayBuilder fds = new IntArrayBuilder();
181188
PSequence pSequence = constructListNode.execute(sequence);
189+
boolean containsSocket = false;
182190
for (int i = 0; i < sequenceLib.lengthWithState(sequence, threadState); i++) {
183191
Object pythonObject = callGetItemNode.executeObject(frame, pSequence, i);
184192
objects.add(pythonObject);
185-
fds.add(itemLib.asFileDescriptorWithState(pythonObject, threadState));
193+
int fd = itemLib.asFileDescriptorWithState(pythonObject, threadState);
194+
fds.add(fd);
195+
containsSocket |= resources.isSocket(fd);
186196
}
187-
return new ObjAndFDList(objects.toArray(new Object[0]), fds.toArray());
197+
return new ObjAndFDList(objects.toArray(new Object[0]), fds.toArray(), containsSocket);
188198
}
189199

190200
@ValueType
191201
private static final class ObjAndFDList {
192202
private final Object[] objects;
193203
private final int[] fds;
204+
private final boolean containsSocket; // TODO remove when native sockets are supported
194205

195-
private ObjAndFDList(Object[] objects, int[] fds) {
206+
private ObjAndFDList(Object[] objects, int[] fds, boolean containsSocket) {
196207
this.objects = objects;
197208
this.fds = fds;
209+
this.containsSocket = containsSocket;
198210
}
199211
}
200212

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ Object socket(VirtualFrame frame, Object cls, Object family, Object type, Object
285285
private Object createSocketInternal(Object cls, int family, int type, int proto) {
286286
if (getContext().getEnv().isNativeAccessAllowed()) {
287287
PSocket newSocket = factory().createSocket(cls, family, type, proto);
288-
int fd = getContext().getResources().openSocket(newSocket);
288+
int fd = getContext().getResources().openSocket(newSocket, getContext());
289289
newSocket.setFileno(fd);
290290
return newSocket;
291291
} else {
@@ -680,7 +680,7 @@ Object close(VirtualFrame frame, int fd) {
680680
} catch (IOException e) {
681681
throw raiseOSError(frame, OSErrorEnum.EBADF);
682682
}
683-
getContext().getResources().close(socket.getFileno());
683+
getContext().getResources().closeSocket(socket, getContext());
684684
return PNone.NONE;
685685
}
686686

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ Object accept(PSocket socket) {
137137
throw raise(OSError);
138138
}
139139
PSocket newSocket = factory().createSocket(socket.getFamily(), socket.getType(), socket.getProto());
140-
int fd = getContext().getResources().openSocket(newSocket);
140+
int fd = getContext().getResources().openSocket(newSocket, getContext());
141141
newSocket.setFileno(fd);
142142
newSocket.setSocket(acceptSocket);
143143
SocketUtils.setBlocking(newSocket, socket.isBlocking());
@@ -178,6 +178,10 @@ abstract static class CloseNode extends PythonUnaryBuiltinNode {
178178
@Specialization
179179
@TruffleBoundary
180180
Object close(PSocket socket) {
181+
if (!socket.isOpen()) {
182+
return PNone.NONE;
183+
}
184+
181185
if (socket.getSocket() != null) {
182186
try {
183187
socket.getSocket().close();
@@ -191,7 +195,7 @@ Object close(PSocket socket) {
191195
throw raise(OSError, ErrorMessages.BAD_FILE_DESCRIPTOR);
192196
}
193197
}
194-
getContext().getResources().close(socket.getFileno());
198+
getContext().getResources().closeSocket(socket, getContext());
195199
return PNone.NONE;
196200
}
197201
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeva
459459
continue errfdsCheck;
460460
}
461461
}
462-
compatibilityIgnored("POSIX emultaion layer doesn't support waiting on exceptional conditions in select()");
462+
compatibilityIgnored("POSIX emulation layer doesn't support waiting on exceptional conditions in select()");
463463
break;
464464
}
465465

@@ -988,7 +988,7 @@ private int getEmulatedInode(TruffleFile file) {
988988
// best effort
989989
canonical = file.getAbsoluteFile();
990990
}
991-
return context.getResources().getInodeId(canonical.getPath());
991+
return getInodeId(canonical.getPath());
992992
}
993993

994994
@TruffleBoundary(allowInlining = true)

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

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
import java.util.TreeMap;
5959

6060
import com.oracle.graal.python.builtins.objects.socket.PSocket;
61+
import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException;
62+
import com.oracle.truffle.api.CompilerDirectives;
6163
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
6264
import com.oracle.truffle.api.TruffleFile;
6365
import com.oracle.truffle.api.TruffleLanguage.Env;
@@ -327,15 +329,59 @@ public void close(int fd) {
327329
}
328330
}
329331

332+
// Until the socket module is rewritten to use PosixSupportLibrary, we need to deal with
333+
// emulated sockets when graalpython runs with the NFI posix backend. Mainly we need to
334+
// distinguish whether a fd is a real native file descriptor, or if it is an emulated socket.
335+
// Thus we must 'reserve' a native fd for each emulated socket - we do that by dup()-ing
336+
// a fd which we get by calling native pipe().
337+
// We also assume that fds returned from openSocket are used only through the socket module
338+
// i.e. calls like posix.close(fd) or posix.read(fd) don't do the right thing.
339+
private int nativeFdForSockets = -1;
340+
330341
@TruffleBoundary
331-
public int openSocket(PSocket socket) {
342+
public int openSocket(PSocket socket, PythonContext context) {
343+
Object posixSupport = context.getPosixSupport();
332344
synchronized (files) {
333-
int fd = nextFreeFd();
345+
int fd;
346+
if (posixSupport == this) {
347+
// using emulated backend
348+
fd = nextFreeFd();
349+
} else {
350+
// using nfi backend
351+
try {
352+
PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached();
353+
if (nativeFdForSockets == -1) {
354+
nativeFdForSockets = posixLib.pipe(posixSupport)[0];
355+
}
356+
fd = posixLib.dup(posixSupport, nativeFdForSockets);
357+
} catch (PosixException e) {
358+
throw CompilerDirectives.shouldNotReachHere("Unable to assign native fd to a socket", e);
359+
}
360+
}
334361
addFD(fd, socket);
335362
return fd;
336363
}
337364
}
338365

366+
@TruffleBoundary
367+
public void closeSocket(PSocket socket, PythonContext context) {
368+
int fd = socket.getFileno();
369+
close(fd);
370+
Object posixSupport = context.getPosixSupport();
371+
if (posixSupport != this) {
372+
// using nfi backend
373+
try {
374+
PosixSupportLibrary.getUncached().close(posixSupport, fd);
375+
} catch (PosixException e) {
376+
throw CompilerDirectives.shouldNotReachHere("Unable to close native fd", e);
377+
}
378+
}
379+
}
380+
381+
public boolean isSocket(int fd) {
382+
return getSocket(fd) != null;
383+
}
384+
339385
@TruffleBoundary
340386
public void reopenSocket(PSocket socket, int fd) {
341387
addFD(fd, socket);

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ private static final class AtExitHook {
262262
@CompilationFinal(dimensions = 1) private final PythonNativeWrapper[] singletonNativePtrs = new PythonNativeWrapper[PythonLanguage.getNumberOfSpecialSingletons()];
263263

264264
// The context-local resources
265-
private PosixResources resources;
265+
private EmulatedPosixSupport resources;
266266
private final AsyncHandler handler;
267267
private final AsyncHandler.SharedFinalizer sharedFinalizer;
268268

@@ -583,11 +583,11 @@ private void initalizePosixSupport() {
583583
} else if (ImageInfo.inImageRuntimeCode()) {
584584
NFIPosixSupport nativePosixSupport = new NFIPosixSupport(this, option);
585585
result = new ImageBuildtimePosixSupport(nativePosixSupport, null);
586-
resources = new PosixResources();
586+
resources = new EmulatedPosixSupport(this);
587587
resources.setEnv(env);
588588
} else {
589589
result = new NFIPosixSupport(this, option);
590-
resources = new PosixResources();
590+
resources = new EmulatedPosixSupport(this);
591591
resources.setEnv(env);
592592
}
593593
break;
@@ -926,7 +926,7 @@ public boolean isExecutableAccessAllowed() {
926926
return getEnv().isHostLookupAllowed() || getEnv().isNativeAccessAllowed();
927927
}
928928

929-
public PosixResources getResources() {
929+
public EmulatedPosixSupport getResources() {
930930
return resources;
931931
}
932932

0 commit comments

Comments
 (0)