|
@@ -0,0 +1,168 @@
|
|
|
|
+/*
|
|
|
|
+ * Licensed to the Apache Software Foundation (ASF) under one
|
|
|
|
+ * or more contributor license agreements. See the NOTICE file
|
|
|
|
+ * distributed with this work for additional information
|
|
|
|
+ * regarding copyright ownership. The ASF licenses this file
|
|
|
|
+ * to you under the Apache License, Version 2.0 (the
|
|
|
|
+ * "License"); you may not use this file except in compliance
|
|
|
|
+ * with the License. You may obtain a copy of the License at
|
|
|
|
+ *
|
|
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
+ *
|
|
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
+ * See the License for the specific language governing permissions and
|
|
|
|
+ * limitations under the License.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+package org.apache.hadoop.util;
|
|
|
|
+
|
|
|
|
+import org.apache.hadoop.classification.InterfaceAudience;
|
|
|
|
+
|
|
|
|
+import org.apache.hadoop.util.dynamic.BindingUtils;
|
|
|
|
+import org.apache.hadoop.util.dynamic.DynConstructors;
|
|
|
|
+import org.apache.hadoop.util.dynamic.DynMethods;
|
|
|
|
+
|
|
|
|
+import java.lang.reflect.Method;
|
|
|
|
+import java.lang.reflect.Proxy;
|
|
|
|
+
|
|
|
|
+@InterfaceAudience.Private
|
|
|
|
+public class SignalUtil {
|
|
|
|
+
|
|
|
|
+ static final Class<?> JDK_SIGNAL_CLAZZ =
|
|
|
|
+ BindingUtils.loadClassSafely("sun.misc.Signal");
|
|
|
|
+ static final Class<?> JDK_SIGNAL_HANDLER_CLAZZ =
|
|
|
|
+ BindingUtils.loadClassSafely("sun.misc.SignalHandler");
|
|
|
|
+
|
|
|
|
+ static final DynConstructors.Ctor<?> JDK_SIGNAL_CTOR =
|
|
|
|
+ new DynConstructors.Builder()
|
|
|
|
+ .impl(JDK_SIGNAL_CLAZZ, String.class)
|
|
|
|
+ .build();
|
|
|
|
+
|
|
|
|
+ static final DynMethods.StaticMethod JDK_SIGNAL_HANDLE_STATIC_METHOD =
|
|
|
|
+ new DynMethods.Builder("handle")
|
|
|
|
+ .impl(JDK_SIGNAL_CLAZZ, JDK_SIGNAL_CLAZZ, JDK_SIGNAL_HANDLER_CLAZZ)
|
|
|
|
+ .buildStatic();
|
|
|
|
+
|
|
|
|
+ static final DynMethods.StaticMethod JDK_SIGNAL_RAISE_STATIC_METHOD =
|
|
|
|
+ new DynMethods.Builder("raise")
|
|
|
|
+ .impl(JDK_SIGNAL_CLAZZ, JDK_SIGNAL_CLAZZ)
|
|
|
|
+ .buildStatic();
|
|
|
|
+
|
|
|
|
+ static final DynMethods.UnboundMethod JDK_SIGNAL_HANDLER_HANDLE_UNBOUND_METHOD =
|
|
|
|
+ new DynMethods.Builder("handle")
|
|
|
|
+ .impl(JDK_SIGNAL_HANDLER_CLAZZ, JDK_SIGNAL_CLAZZ)
|
|
|
|
+ .build();
|
|
|
|
+
|
|
|
|
+ @InterfaceAudience.Private
|
|
|
|
+ public static class Signal {
|
|
|
|
+ private static final DynMethods.UnboundMethod GET_NUMBER_UNBOUND_METHOD =
|
|
|
|
+ new DynMethods.Builder("getNumber").impl(JDK_SIGNAL_CLAZZ).build();
|
|
|
|
+
|
|
|
|
+ private static final DynMethods.UnboundMethod GET_NAME_UNBOUND_METHOD =
|
|
|
|
+ new DynMethods.Builder("getName").impl(JDK_SIGNAL_CLAZZ).build();
|
|
|
|
+
|
|
|
|
+ private final Object/* sun.misc.Signal */ delegate;
|
|
|
|
+ private final DynMethods.BoundMethod getNumberMethod;
|
|
|
|
+ private final DynMethods.BoundMethod getNameMethod;
|
|
|
|
+
|
|
|
|
+ public Signal(String name) {
|
|
|
|
+ Preconditions.checkNotNull(name);
|
|
|
|
+ this.delegate = JDK_SIGNAL_CTOR.newInstance(name);
|
|
|
|
+ this.getNumberMethod = GET_NUMBER_UNBOUND_METHOD.bind(delegate);
|
|
|
|
+ this.getNameMethod = GET_NAME_UNBOUND_METHOD.bind(delegate);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public Signal(Object delegate) {
|
|
|
|
+ Preconditions.checkArgument(JDK_SIGNAL_CLAZZ.isInstance(delegate),
|
|
|
|
+ String.format("Expected class is '%s', but actual class is '%s'",
|
|
|
|
+ JDK_SIGNAL_CLAZZ.getName(), delegate.getClass().getName()));
|
|
|
|
+ this.delegate = delegate;
|
|
|
|
+ this.getNumberMethod = GET_NUMBER_UNBOUND_METHOD.bind(delegate);
|
|
|
|
+ this.getNameMethod = GET_NAME_UNBOUND_METHOD.bind(delegate);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public int getNumber() {
|
|
|
|
+ return getNumberMethod.invoke();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public String getName() {
|
|
|
|
+ return getNameMethod.invoke();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean equals(Object obj) {
|
|
|
|
+ if (this == obj) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ if (obj instanceof Signal) {
|
|
|
|
+ return delegate.equals(((Signal)obj).delegate);
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int hashCode() {
|
|
|
|
+ return delegate.hashCode();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public String toString() {
|
|
|
|
+ return delegate.toString();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @InterfaceAudience.Private
|
|
|
|
+ public interface Handler {
|
|
|
|
+ void handle(Signal sig);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static class JdkSignalHandlerImpl implements Handler {
|
|
|
|
+
|
|
|
|
+ private final Object/* sun.misc.SignalHandler */ delegate;
|
|
|
|
+ private final DynMethods.BoundMethod jdkSignalHandlerHandleMethod;
|
|
|
|
+
|
|
|
|
+ JdkSignalHandlerImpl(Handler handler) {
|
|
|
|
+ this.delegate = Proxy.newProxyInstance(
|
|
|
|
+ getClass().getClassLoader(),
|
|
|
|
+ new Class<?>[] {JDK_SIGNAL_HANDLER_CLAZZ},
|
|
|
|
+ (proxyObj, method, args) -> {
|
|
|
|
+ if ("handle".equals(method.getName()) && args.length == 1
|
|
|
|
+ && JDK_SIGNAL_CLAZZ.isInstance(args[0])) {
|
|
|
|
+ handler.handle(new Signal(args[0]));
|
|
|
|
+ return null;
|
|
|
|
+ } else {
|
|
|
|
+ Method delegateMethod = handler.getClass().getMethod(
|
|
|
|
+ method.getName(), method.getParameterTypes());
|
|
|
|
+ return delegateMethod.invoke(handler, args);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ this.jdkSignalHandlerHandleMethod = JDK_SIGNAL_HANDLER_HANDLE_UNBOUND_METHOD.bind(delegate);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ JdkSignalHandlerImpl(Object delegate) {
|
|
|
|
+ Preconditions.checkArgument(JDK_SIGNAL_HANDLER_CLAZZ.isInstance(delegate),
|
|
|
|
+ String.format("Expected class is '%s', but actual class is '%s'",
|
|
|
|
+ JDK_SIGNAL_HANDLER_CLAZZ.getName(), delegate.getClass().getName()));
|
|
|
|
+ this.delegate = delegate;
|
|
|
|
+ this.jdkSignalHandlerHandleMethod = JDK_SIGNAL_HANDLER_HANDLE_UNBOUND_METHOD.bind(delegate);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void handle(Signal sig) {
|
|
|
|
+ jdkSignalHandlerHandleMethod.invoke(sig.delegate);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Handler handle(Signal sig, Handler handler) {
|
|
|
|
+ Object preHandle = JDK_SIGNAL_HANDLE_STATIC_METHOD.invoke(
|
|
|
|
+ sig.delegate, new JdkSignalHandlerImpl(handler).delegate);
|
|
|
|
+ return new JdkSignalHandlerImpl(preHandle);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void raise(Signal sig) throws IllegalArgumentException {
|
|
|
|
+ JDK_SIGNAL_RAISE_STATIC_METHOD.invoke(sig.delegate);
|
|
|
|
+ }
|
|
|
|
+}
|