Skip to content

Commit 630fa04

Browse files
committed
Wrap existing Java signal handlers
1 parent 2eaca5f commit 630fa04

File tree

4 files changed

+138
-52
lines changed

4 files changed

+138
-52
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ public enum PythonBuiltinClassType implements TruffleObject {
118118
PRLock("RLock", "_thread"),
119119
PSemLock("SemLock", "_multiprocessing"),
120120
PSocket("socket", "_socket"),
121+
PJavaSignalHandler("java_signal_handler"),
121122
PStaticmethod("staticmethod", BuiltinNames.BUILTINS),
122123
PClassmethod("classmethod", BuiltinNames.BUILTINS),
123124
PScandirIterator("ScandirIterator", "posix"),

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

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.oracle.graal.python.builtins.objects.ints.PInt;
5353
import com.oracle.graal.python.builtins.objects.module.PythonModule;
5454
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
55+
import com.oracle.graal.python.builtins.objects.signal.PJavaSignalHandler;
5556
import com.oracle.graal.python.nodes.ErrorMessages;
5657
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
5758
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -62,6 +63,7 @@
6263
import com.oracle.graal.python.runtime.AsyncHandler;
6364
import com.oracle.graal.python.runtime.PythonCore;
6465
import com.oracle.graal.python.runtime.exception.PythonErrorType;
66+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
6567
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
6668
import com.oracle.truffle.api.dsl.Cached;
6769
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
@@ -71,6 +73,8 @@
7173
import com.oracle.truffle.api.library.CachedLibrary;
7274
import com.oracle.truffle.api.object.HiddenKey;
7375

76+
import sun.misc.SignalHandler;
77+
7478
@CoreFunctions(defineModule = "_signal")
7579
public class SignalModuleBuiltins extends PythonBuiltins {
7680
private static ConcurrentHashMap<Integer, Object> signalHandlers = new ConcurrentHashMap<>();
@@ -172,22 +176,35 @@ int alarmOvf(PInt seconds) {
172176
}
173177
}
174178

179+
private static Object handlerToPython(PythonObjectFactory factory, SignalHandler handler, int signum) {
180+
if (handler == sun.misc.SignalHandler.SIG_DFL) {
181+
return Signals.SIG_DFL;
182+
} else if (handler == sun.misc.SignalHandler.SIG_IGN) {
183+
return Signals.SIG_IGN;
184+
} else if (handler instanceof Signals.PythonSignalHandler) {
185+
if (signalHandlers.containsKey(signum)) {
186+
return signalHandlers.get(signum);
187+
} else {
188+
return PNone.NONE;
189+
}
190+
} else {
191+
return factory.createJavaSignalHandler(handler);
192+
}
193+
}
194+
175195
@Builtin(name = "getsignal", minNumOfPositionalArgs = 1)
176196
@GenerateNodeFactory
177197
abstract static class GetSignalNode extends PythonUnaryBuiltinNode {
178198
@Specialization
179199
@TruffleBoundary
180200
Object getsignal(int signum) {
181-
int currentSignalHandler = Signals.getCurrentSignalHandler(signum);
182-
if (currentSignalHandler == Signals.SIG_UNKNOWN) {
183-
if (signalHandlers.containsKey(signum)) {
184-
return signalHandlers.get(signum);
185-
} else {
186-
return PNone.NONE;
187-
}
188-
} else {
189-
return currentSignalHandler;
190-
}
201+
return handlerToPython(factory(), Signals.getCurrentSignalHandler(signum), signum);
202+
}
203+
204+
@Specialization(limit = "3")
205+
Object getsignal(Object signum,
206+
@CachedLibrary("signum") PythonObjectLibrary lib) {
207+
return getsignal(lib.asSize(signum));
191208
}
192209
}
193210

@@ -205,7 +222,7 @@ Object defaultIntHandler(@SuppressWarnings("unused") Object[] args) {
205222
@GenerateNodeFactory
206223
abstract static class SignalNode extends PythonTernaryBuiltinNode {
207224

208-
@Specialization(guards = "!idNumLib.isCallable(idNum)", limit = "1")
225+
@Specialization(guards = {"!idNumLib.isCallable(idNum)", "!isJavaHandler(idNum)"}, limit = "1")
209226
Object signalId(@SuppressWarnings("unused") PythonModule self, Object signal, Object idNum,
210227
@SuppressWarnings("unused") @CachedLibrary("idNum") PythonObjectLibrary idNumLib,
211228
@CachedLibrary("signal") PythonObjectLibrary signalLib) {
@@ -218,21 +235,28 @@ Object signalId(@SuppressWarnings("unused") PythonModule self, Object signal, Ob
218235

219236
@TruffleBoundary
220237
private Object signal(int signum, int id) {
221-
Object retval;
238+
SignalHandler oldHandler;
222239
try {
223-
retval = Signals.setSignalHandler(signum, id);
240+
oldHandler = Signals.setSignalHandler(signum, id);
224241
} catch (IllegalArgumentException e) {
225242
throw raise(PythonErrorType.TypeError, ErrorMessages.SIGNAL_MUST_BE_SIGIGN_SIGDFL_OR_CALLABLE_OBJ);
226243
}
227-
if ((int) retval == Signals.SIG_UNKNOWN) {
228-
if (signalHandlers.containsKey(signum)) {
229-
retval = signalHandlers.get(signum);
230-
} else {
231-
retval = PNone.NONE;
232-
}
233-
}
234244
signalHandlers.put(signum, id);
235-
return retval;
245+
return handlerToPython(factory(), oldHandler, signum);
246+
}
247+
248+
@Specialization(limit = "1")
249+
Object signalHandler(@SuppressWarnings("unused") PythonModule self, Object signal, PJavaSignalHandler handler,
250+
@CachedLibrary("signal") PythonObjectLibrary signalLib) {
251+
int signum = signalLib.asSize(signal);
252+
SignalHandler oldHandler;
253+
try {
254+
oldHandler = Signals.setSignalHandler(signum, handler.getHandler());
255+
} catch (IllegalArgumentException e) {
256+
throw raise(PythonErrorType.ValueError, e);
257+
}
258+
signalHandlers.remove(signum);
259+
return handlerToPython(factory(), oldHandler, signum);
236260
}
237261

238262
@Specialization(guards = "handlerLib.isCallable(handler)", limit = "1")
@@ -248,25 +272,18 @@ Object signalHandler(PythonModule self, Object signal, Object handler,
248272
private Object signal(PythonModule self, int signum, Object handler, ReadAttributeFromObjectNode readQueueNode, ReadAttributeFromObjectNode readSemaNode) {
249273
ConcurrentLinkedDeque<SignalTriggerAction> queue = getQueue(self, readQueueNode);
250274
Semaphore semaphore = getSemaphore(self, readSemaNode);
251-
Object retval;
275+
SignalHandler oldHandler;
252276
SignalTriggerAction signalTrigger = new SignalTriggerAction(handler, signum);
253277
try {
254-
retval = Signals.setSignalHandler(signum, () -> {
278+
oldHandler = Signals.setSignalHandler(signum, () -> {
255279
queue.add(signalTrigger);
256280
semaphore.release();
257281
});
258282
} catch (IllegalArgumentException e) {
259283
throw raise(PythonErrorType.ValueError, e);
260284
}
261-
if ((int) retval == Signals.SIG_UNKNOWN) {
262-
if (signalHandlers.containsKey(signum)) {
263-
retval = signalHandlers.get(signum);
264-
} else {
265-
retval = PNone.NONE;
266-
}
267-
}
268285
signalHandlers.put(signum, handler);
269-
return retval;
286+
return handlerToPython(factory(), oldHandler, signum);
270287
}
271288

272289
@SuppressWarnings("unchecked")
@@ -288,6 +305,10 @@ private static Semaphore getSemaphore(PythonModule self, ReadAttributeFromObject
288305
throw new IllegalStateException("the signal trigger semaphore was modified!");
289306
}
290307
}
308+
309+
protected static boolean isJavaHandler(Object obj) {
310+
return obj instanceof PJavaSignalHandler;
311+
}
291312
}
292313
}
293314

@@ -299,7 +320,6 @@ private static Semaphore getSemaphore(PythonModule self, ReadAttributeFromObject
299320
final class Signals {
300321
static final int SIG_DFL = 0;
301322
static final int SIG_IGN = 1;
302-
static final int SIG_UNKNOWN = -1;
303323
private static final int SIGMAX = 31;
304324
static final String[] signalNames = new String[SIGMAX + 1];
305325

@@ -342,7 +362,7 @@ synchronized static void scheduleAlarm(long seconds) {
342362
new Thread(new Alarm(seconds)).start();
343363
}
344364

345-
private static class PythonSignalHandler implements sun.misc.SignalHandler {
365+
static class PythonSignalHandler implements sun.misc.SignalHandler {
346366
private final Runnable handler;
347367

348368
public PythonSignalHandler(Runnable handler) {
@@ -360,13 +380,17 @@ static String signalNumberToName(int signum) {
360380
}
361381

362382
@TruffleBoundary
363-
synchronized static int setSignalHandler(int signum, Runnable handler) throws IllegalArgumentException {
364-
sun.misc.SignalHandler oldH = sun.misc.Signal.handle(new sun.misc.Signal(signalNumberToName(signum)), new PythonSignalHandler(handler));
365-
return handlerToInt(oldH);
383+
synchronized static SignalHandler setSignalHandler(int signum, Runnable handler) throws IllegalArgumentException {
384+
return setSignalHandler(signum, new PythonSignalHandler(handler));
385+
}
386+
387+
@TruffleBoundary
388+
synchronized static SignalHandler setSignalHandler(int signum, SignalHandler handler) throws IllegalArgumentException {
389+
return sun.misc.Signal.handle(new sun.misc.Signal(signalNumberToName(signum)), handler);
366390
}
367391

368392
@TruffleBoundary
369-
synchronized static int setSignalHandler(int signum, int handler) throws IllegalArgumentException {
393+
synchronized static SignalHandler setSignalHandler(int signum, int handler) throws IllegalArgumentException {
370394
sun.misc.SignalHandler h;
371395
if (handler == SIG_DFL) {
372396
h = sun.misc.SignalHandler.SIG_DFL;
@@ -375,34 +399,24 @@ synchronized static int setSignalHandler(int signum, int handler) throws Illegal
375399
} else {
376400
throw new IllegalArgumentException();
377401
}
378-
return handlerToInt(sun.misc.Signal.handle(new sun.misc.Signal(signalNumberToName(signum)), h));
402+
return sun.misc.Signal.handle(new sun.misc.Signal(signalNumberToName(signum)), h);
379403
}
380404

381405
@TruffleBoundary
382-
synchronized static int getCurrentSignalHandler(int signum) {
406+
synchronized static SignalHandler getCurrentSignalHandler(int signum) {
383407
// To check what the current signal handler, we install default to get the current one
384408
// and immediately replace it again.
385409
sun.misc.SignalHandler oldH;
386410
try {
387411
oldH = sun.misc.Signal.handle(new sun.misc.Signal(signalNumberToName(signum)), sun.misc.SignalHandler.SIG_DFL);
388412
} catch (IllegalArgumentException e) {
389-
return SIG_DFL;
413+
return sun.misc.SignalHandler.SIG_DFL;
390414
}
391415
try {
392416
sun.misc.Signal.handle(new sun.misc.Signal(signalNumberToName(signum)), oldH);
393417
} catch (IllegalArgumentException e) {
394-
return SIG_DFL;
395-
}
396-
return handlerToInt(oldH);
397-
}
398-
399-
private static int handlerToInt(sun.misc.SignalHandler oldH) {
400-
if (oldH == sun.misc.SignalHandler.SIG_DFL) {
401-
return SIG_DFL;
402-
} else if (oldH == sun.misc.SignalHandler.SIG_IGN) {
403-
return SIG_IGN;
404-
} else {
405-
return SIG_UNKNOWN;
418+
return sun.misc.SignalHandler.SIG_DFL;
406419
}
420+
return oldH;
407421
}
408422
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.objects.signal;
42+
43+
import com.oracle.graal.python.builtins.objects.object.PythonObject;
44+
import com.oracle.truffle.api.object.Shape;
45+
46+
import sun.misc.SignalHandler;
47+
48+
public class PJavaSignalHandler extends PythonObject {
49+
private final SignalHandler handler;
50+
51+
public PJavaSignalHandler(Object pythonClass, Shape instanceShape, SignalHandler handler) {
52+
super(pythonClass, instanceShape);
53+
this.handler = handler;
54+
}
55+
56+
public SignalHandler getHandler() {
57+
return handler;
58+
}
59+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PythonObjectFactory.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
import com.oracle.graal.python.builtins.objects.set.PBaseSet;
109109
import com.oracle.graal.python.builtins.objects.set.PFrozenSet;
110110
import com.oracle.graal.python.builtins.objects.set.PSet;
111+
import com.oracle.graal.python.builtins.objects.signal.PJavaSignalHandler;
111112
import com.oracle.graal.python.builtins.objects.slice.PIntSlice;
112113
import com.oracle.graal.python.builtins.objects.slice.PObjectSlice;
113114
import com.oracle.graal.python.builtins.objects.socket.PSocket;
@@ -155,6 +156,8 @@
155156
import com.oracle.truffle.api.object.DynamicObject;
156157
import com.oracle.truffle.api.object.Shape;
157158

159+
import sun.misc.SignalHandler;
160+
158161
@GenerateUncached
159162
@ImportStatic(PythonOptions.class)
160163
@ReportPolymorphism
@@ -858,6 +861,15 @@ public PSocket createSocket(Object cls, int family, int type, int proto, int fil
858861
return trace(new PSocket(cls, getShape(cls), family, type, proto, fileno));
859862
}
860863

864+
/*
865+
* Signal
866+
*/
867+
868+
public PJavaSignalHandler createJavaSignalHandler(SignalHandler handler) {
869+
PythonBuiltinClassType cls = PythonBuiltinClassType.PJavaSignalHandler;
870+
return trace(new PJavaSignalHandler(cls, getShape(cls), handler));
871+
}
872+
861873
/*
862874
* Threading
863875
*/

0 commit comments

Comments
 (0)