001: /*
002: * Created on Jan 31, 2004
003: *
004: * Class to trap OS signals without relying on the existance of
005: * the unsupported Sun signal handling classes.
006: */
007: package sisc.util;
008:
009: import java.lang.reflect.*;
010: import java.security.AccessControlException;
011: import java.util.ArrayList;
012: import java.util.HashMap;
013: import java.util.List;
014: import java.util.Map;
015:
016: import sisc.data.Procedure;
017: import sisc.env.DynamicEnvironment;
018: import sisc.interpreter.Context;
019: import sisc.interpreter.Interpreter;
020: import sisc.interpreter.SchemeCaller;
021: import sisc.interpreter.SchemeException;
022:
023: /**
024: * Traps signals using the unsupported Sun classes for
025: * signal handling, to provide Scheme callbacks on those signals.
026: */
027: public class SignalHook implements InvocationHandler {
028:
029: private static Method handle;
030: private static Class csignal, csignalHandler;
031: private static Constructor sigcons;
032: private static Object SIG_DFL;
033: private static Object sigHook;
034:
035: //Determine if we even *have* sun.misc.*
036: static {
037: try {
038: csignal = Class.forName("sun.misc.Signal");
039: csignalHandler = Class.forName("sun.misc.SignalHandler");
040: } catch (ClassNotFoundException cnf) {
041: } catch (AccessControlException ace) {
042: //Apparently this can happen on some JVMs, despite not being
043: //declared throwable in Class.forName.
044: }
045: }
046:
047: static {
048: if (csignalHandler != null) {
049: try {
050: handle = csignal.getMethod("handle", new Class[] {
051: csignal, csignalHandler });
052: SIG_DFL = csignalHandler.getField("SIG_DFL").get(null);
053: sigHook = Proxy.newProxyInstance(csignalHandler
054: .getClassLoader(),
055: new Class[] { csignalHandler },
056: new SignalHook());
057: sigcons = csignal
058: .getConstructor(new Class[] { String.class });
059: } catch (Exception nsm) {
060: nsm.printStackTrace();
061: csignalHandler = null;
062: }
063: }
064: }
065:
066: private static Map handlers = new HashMap();
067:
068: public static class SignalHandler implements SchemeCaller {
069: private Procedure proc;
070: private DynamicEnvironment env;
071:
072: public SignalHandler(Procedure proc, DynamicEnvironment env) {
073: this .proc = proc;
074: this .env = env;
075: }
076:
077: public boolean equals(Object o) {
078: if (!(o instanceof SignalHandler))
079: return false;
080: SignalHandler ot = (SignalHandler) o;
081: return ot.proc.equals(proc);
082: }
083:
084: public Object execute(Interpreter r) throws SchemeException {
085: return r.eval(proc, Util.ZV);
086: }
087: }
088:
089: private static Object makeSignal(String signame) {
090: Object signal = null;
091: if (csignalHandler != null) {
092: try {
093: signal = sigcons.newInstance(new Object[] { signame });
094: } catch (Exception ie) {
095: }
096: }
097: return signal;
098: }
099:
100: public static void addHandler(String signame, Procedure proc,
101: DynamicEnvironment env) {
102: Object signal = makeSignal(signame);
103: if (signal == null)
104: return;
105:
106: synchronized (handlers) {
107: List l = (List) handlers.get(signal);
108: if (l == null) {
109: l = new ArrayList();
110: handlers.put(signal, l);
111: l.add(new SignalHandler(proc, env));
112: try {
113: handle.invoke(null,
114: new Object[] { signal, sigHook });
115: } catch (InvocationTargetException it) {
116: if (!(it.getTargetException() instanceof IllegalArgumentException)) {
117: it.getTargetException().printStackTrace();
118: }
119: // The underlying VM doesn't support overriding this
120: // signal, so we ignore it.
121: } catch (Exception e) {
122: e.printStackTrace();
123: }
124: } else {
125: synchronized (l) {
126: l.add(new SignalHandler(proc, env));
127: }
128: }
129: }
130: }
131:
132: public static void removeHandler(String signame, Procedure proc,
133: DynamicEnvironment env) {
134: Object signal = makeSignal(signame);
135: if (signal == null)
136: return;
137:
138: SignalHandler handler = new SignalHandler(proc, env);
139: List l;
140: synchronized (handlers) {
141: l = (List) handlers.get(signal);
142: }
143: if (l != null) {
144: synchronized (l) {
145: l.remove(handler);
146: if (l.isEmpty()) {
147: try {
148: handle.invoke(null, new Object[] { signal,
149: SIG_DFL });
150: } catch (Exception iae) {
151: }
152: handlers.remove(signal);
153: }
154: }
155: }
156: }
157:
158: public Object invoke(Object o, Method m, Object[] a) {
159: try {
160: if (a == null || a.length != 1)
161: return null;
162: Object signal = a[0];
163: List l;
164: synchronized (handlers) {
165: l = (List) handlers.get(signal);
166: }
167: if (l != null) {
168: synchronized (l) {
169: for (int i = 0; i < l.size(); i++) {
170: SignalHandler handler = (SignalHandler) l
171: .get(i);
172: try {
173: Interpreter r = Context
174: .currentInterpreter(handler.env.ctx);
175: Context.execute((r == null ? handler.env
176: .copy() : r.dynenv), handler);
177: } catch (SchemeException e) {
178: e.printStackTrace();
179: }
180: }
181: }
182: }
183: } catch (Exception t) {
184: t.printStackTrace();
185: }
186: return null;
187: }
188: }
189:
190: /*
191: * The contents of this file are subject to the Mozilla Public
192: * License Version 1.1 (the "License"); you may not use this file
193: * except in compliance with the License. You may obtain a copy of
194: * the License at http://www.mozilla.org/MPL/
195: *
196: * Software distributed under the License is distributed on an "AS
197: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
198: * implied. See the License for the specific language governing
199: * rights and limitations under the License.
200: *
201: * The Original Code is the Second Interpreter of Scheme Code (SISC).
202: *
203: * The Initial Developer of the Original Code is Scott G. Miller.
204: * Portions created by Scott G. Miller are Copyright (C) 2000-2007
205: * Scott G. Miller. All Rights Reserved.
206: *
207: * Contributor(s):
208: * Matthias Radestock
209: *
210: * Alternatively, the contents of this file may be used under the
211: * terms of the GNU General Public License Version 2 or later (the
212: * "GPL"), in which case the provisions of the GPL are applicable
213: * instead of those above. If you wish to allow use of your
214: * version of this file only under the terms of the GPL and not to
215: * allow others to use your version of this file under the MPL,
216: * indicate your decision by deleting the provisions above and
217: * replace them with the notice and other provisions required by
218: * the GPL. If you do not delete the provisions above, a recipient
219: * may use your version of this file under either the MPL or the
220: * GPL.
221: */
|