source: branches/0.16.x/abcl/src/org/armedbear/lisp/LispThread.java

Last change on this file was 12105, checked in by Mark Evenson, 16 years ago

Split StackFrame? abstraction into Java and Lisp stack frames.

From the original patch/idea from Tobias Rittweiler this introduces
more information of primary interest to ABCL implemnters such as when
a form like (make-thread #'(lambda ())) is evaluated

All users of EXT:BACKTRACE-AS-LIST should now use SYS:BACKTRACE, the
results of which is a list of the new builtin classes JAVA_STACK_FRAME
or LISP_STACK_FRAME. The methods SYS:FRAME-TO-STRING and
SYS:FRAME-TO-LIST are defined to break these new objects into
inspectable parts. As a convenience, there is a SYS:BACKTRACE-AS-LIST
which calls SYS:FRAME-TO-LIST to each element of the computed
backtrace.

Refactorings have occurred on the Java side: the misnamed
LispThread?.backtrace() is now LispThread?.printBacktrace().
LispThread?.backtraceAsList() is now LispThread?.backtrace() as it is
a shorter name, and more to the point.

Java stack frames only appear after a call through Lisp.error(), which
has only the top level as a restart as an option.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 36.3 KB
Line 
1/*
2 * LispThread.java
3 *
4 * Copyright (C) 2003-2007 Peter Graves
5 * $Id: LispThread.java 12105 2009-08-19 14:51:56Z mevenson $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import java.util.Iterator;
37import java.util.concurrent.ConcurrentHashMap;
38
39public final class LispThread extends LispObject
40{
41    private static boolean use_fast_calls = false;
42
43    // use a concurrent hashmap: we may want to add threads
44    // while at the same time iterating the hash
45    final private static ConcurrentHashMap<Thread,LispThread> map =
46       new ConcurrentHashMap<Thread,LispThread>();
47
48    private static ThreadLocal<LispThread> threads = new ThreadLocal<LispThread>(){
49        @Override
50        public LispThread initialValue() {
51            Thread thisThread = Thread.currentThread();
52            LispThread thread = LispThread.map.get(thisThread);
53            if (thread == null) {
54                thread = new LispThread(thisThread);
55                LispThread.map.put(thisThread,thread);
56            }
57            return thread;
58        }
59    };
60
61    public static final LispThread currentThread()
62    {
63        return threads.get();
64    }
65
66    private final Thread javaThread;
67    private boolean destroyed;
68    private final LispObject name;
69    public SpecialBinding lastSpecialBinding;
70    public LispObject[] _values;
71    private boolean threadInterrupted;
72    private LispObject pending = NIL;
73
74    private LispThread(Thread javaThread)
75    {
76        this.javaThread = javaThread;
77        name = new SimpleString(javaThread.getName());
78    }
79
80    private LispThread(final Function fun, LispObject name)
81    {
82        Runnable r = new Runnable() {
83            public void run()
84            {
85                try {
86                    funcall(fun, new LispObject[0], LispThread.this);
87                }
88                catch (ThreadDestroyed ignored) {
89                      // Might happen.
90                }
91                catch (Throwable t) {
92                    if (isInterrupted()) {
93                        try {
94                            processThreadInterrupts();
95                        }
96                        catch (ConditionThrowable c) {
97                            Debug.trace(c);
98                        }
99                    }
100                }
101                finally {
102                    // make sure the thread is *always* removed from the hash again
103                    map.remove(Thread.currentThread());
104                }
105            }
106        };
107        javaThread = new Thread(r);
108        this.name = name;
109        map.put(javaThread, this);
110        try {
111            javaThread.setName(name.getStringValue());
112        } catch (ConditionThrowable ex) {
113            Debug.trace("Failed to set thread name:");
114      Debug.trace(ex);
115        }
116        javaThread.setDaemon(true);
117        javaThread.start();
118    }
119
120    public StackTraceElement[] getJavaStackTrace() {
121        return javaThread.getStackTrace();
122    }
123
124    @Override
125    public LispObject typeOf()
126    {
127        return Symbol.THREAD;
128    }
129
130    @Override
131    public LispObject classOf()
132    {
133        return BuiltInClass.THREAD;
134    }
135
136    @Override
137    public LispObject typep(LispObject typeSpecifier) throws ConditionThrowable
138    {
139        if (typeSpecifier == Symbol.THREAD)
140            return T;
141        if (typeSpecifier == BuiltInClass.THREAD)
142            return T;
143        return super.typep(typeSpecifier);
144    }
145
146    public final synchronized boolean isDestroyed()
147    {
148        return destroyed;
149    }
150
151    private final synchronized boolean isInterrupted()
152    {
153        return threadInterrupted;
154    }
155
156    private final synchronized void setDestroyed(boolean b)
157    {
158        destroyed = b;
159    }
160
161    private final synchronized void interrupt(LispObject function, LispObject args)
162    {
163        pending = new Cons(args, pending);
164        pending = new Cons(function, pending);
165        threadInterrupted = true;
166        javaThread.interrupt();
167    }
168
169    private final synchronized void processThreadInterrupts()
170        throws ConditionThrowable
171    {
172        while (pending != NIL) {
173            LispObject function = pending.car();
174            LispObject args = pending.cadr();
175            pending = pending.cddr();
176            Primitives.APPLY.execute(function, args);
177        }
178        threadInterrupted = false;
179    }
180
181    public final LispObject[] getValues()
182    {
183        return _values;
184    }
185
186    public final LispObject[] getValues(LispObject result, int count)
187    {
188        if (_values == null) {
189            LispObject[] values = new LispObject[count];
190            if (count > 0)
191                values[0] = result;
192            for (int i = 1; i < count; i++)
193                values[i] = NIL;
194            return values;
195        }
196        // If the caller doesn't want any extra values, just return the ones
197        // we've got.
198        if (count <= _values.length)
199            return _values;
200        // The caller wants more values than we have. Pad with NILs.
201        LispObject[] values = new LispObject[count];
202        for (int i = _values.length; i-- > 0;)
203            values[i] = _values[i];
204        for (int i = _values.length; i < count; i++)
205            values[i] = NIL;
206        return values;
207    }
208
209    // Used by the JVM compiler for MULTIPLE-VALUE-CALL.
210    public final LispObject[] accumulateValues(LispObject result,
211                                               LispObject[] oldValues)
212    {
213        if (oldValues == null) {
214            if (_values != null)
215                return _values;
216            LispObject[] values = new LispObject[1];
217            values[0] = result;
218            return values;
219        }
220        if (_values != null) {
221            if (_values.length == 0)
222                return oldValues;
223            final int totalLength = oldValues.length + _values.length;
224            LispObject[] values = new LispObject[totalLength];
225            System.arraycopy(oldValues, 0,
226                             values, 0,
227                             oldValues.length);
228            System.arraycopy(_values, 0,
229                             values, oldValues.length,
230                             _values.length);
231            return values;
232        }
233        // _values is null.
234        final int totalLength = oldValues.length + 1;
235        LispObject[] values = new LispObject[totalLength];
236        System.arraycopy(oldValues, 0,
237                         values, 0,
238                         oldValues.length);
239        values[totalLength - 1] = result;
240        return values;
241    }
242
243    public final LispObject setValues()
244    {
245        _values = new LispObject[0];
246        return NIL;
247    }
248
249    public final LispObject setValues(LispObject value1)
250    {
251        _values = null;
252        return value1;
253    }
254
255    public final LispObject setValues(LispObject value1, LispObject value2)
256    {
257        _values = new LispObject[2];
258        _values[0] = value1;
259        _values[1] = value2;
260        return value1;
261    }
262
263    public final LispObject setValues(LispObject value1, LispObject value2,
264                                      LispObject value3)
265    {
266        _values = new LispObject[3];
267        _values[0] = value1;
268        _values[1] = value2;
269        _values[2] = value3;
270        return value1;
271    }
272
273    public final LispObject setValues(LispObject value1, LispObject value2,
274                                      LispObject value3, LispObject value4)
275    {
276        _values = new LispObject[4];
277        _values[0] = value1;
278        _values[1] = value2;
279        _values[2] = value3;
280        _values[3] = value4;
281        return value1;
282    }
283
284    public final LispObject setValues(LispObject[] values)
285    {
286        switch (values.length) {
287            case 0:
288                _values = values;
289                return NIL;
290            case 1:
291                _values = null;
292                return values[0];
293            default:
294                _values = values;
295                return values[0];
296        }
297    }
298
299    public final void clearValues()
300    {
301        _values = null;
302    }
303
304    public final LispObject nothing()
305    {
306        _values = new LispObject[0];
307        return NIL;
308    }
309
310    // Forces a single value, for situations where multiple values should be
311    // ignored.
312    public final LispObject value(LispObject obj)
313    {
314        _values = null;
315        return obj;
316    }
317
318    public final void bindSpecial(Symbol name, LispObject value)
319    {
320        lastSpecialBinding = new SpecialBinding(name, value, lastSpecialBinding);
321    }
322
323    public final void bindSpecialToCurrentValue(Symbol name)
324    {
325        SpecialBinding binding = lastSpecialBinding;
326        while (binding != null) {
327            if (binding.name == name) {
328                lastSpecialBinding =
329                    new SpecialBinding(name, binding.value, lastSpecialBinding);
330                return;
331            }
332            binding = binding.next;
333        }
334        // Not found.
335        lastSpecialBinding =
336            new SpecialBinding(name, name.getSymbolValue(), lastSpecialBinding);
337    }
338
339    /** Looks up the value of a special binding in the context of the
340     * given thread.
341     *
342     * In order to find the value of a special variable (in general),
343     * use {@link Symbol#symbolValue}.
344     *
345     * @param name The name of the special variable, normally a symbol
346     * @return The inner most binding of the special, or null if unbound
347     *
348     * @see Symbol#symbolValue
349     */
350    public final LispObject lookupSpecial(LispObject name)
351    {
352        SpecialBinding binding = lastSpecialBinding;
353        while (binding != null) {
354            if (binding.name == name)
355                return binding.value;
356            binding = binding.next;
357        }
358        return null;
359    }
360
361    public final SpecialBinding getSpecialBinding(LispObject name)
362    {
363        SpecialBinding binding = lastSpecialBinding;
364        while (binding != null) {
365            if (binding.name == name)
366                return binding;
367            binding = binding.next;
368        }
369        return null;
370    }
371
372    public final LispObject setSpecialVariable(Symbol name, LispObject value)
373    {
374        SpecialBinding binding = lastSpecialBinding;
375        while (binding != null) {
376            if (binding.name == name) {
377                binding.value = value;
378                return value;
379            }
380            binding = binding.next;
381        }
382        name.setSymbolValue(value);
383        return value;
384    }
385
386    public final LispObject pushSpecial(Symbol name, LispObject thing)
387        throws ConditionThrowable
388    {
389        SpecialBinding binding = lastSpecialBinding;
390        while (binding != null) {
391            if (binding.name == name) {
392                LispObject newValue = new Cons(thing, binding.value);
393                binding.value = newValue;
394                return newValue;
395            }
396            binding = binding.next;
397        }
398        LispObject value = name.getSymbolValue();
399        if (value != null) {
400            LispObject newValue = new Cons(thing, value);
401            name.setSymbolValue(newValue);
402            return newValue;
403        } else
404            return error(new UnboundVariable(name));
405    }
406
407    // Returns symbol value or NIL if unbound.
408    public final LispObject safeSymbolValue(Symbol name)
409    {
410        SpecialBinding binding = lastSpecialBinding;
411        while (binding != null) {
412            if (binding.name == name)
413                return binding.value;
414            binding = binding.next;
415        }
416        LispObject value = name.getSymbolValue();
417        return value != null ? value : NIL;
418    }
419
420    public final void rebindSpecial(Symbol name, LispObject value)
421    {
422        SpecialBinding binding = getSpecialBinding(name);
423        binding.value = value;
424    }
425
426    private LispObject catchTags = NIL;
427
428    public void pushCatchTag(LispObject tag) throws ConditionThrowable
429    {
430        catchTags = new Cons(tag, catchTags);
431    }
432
433    public void popCatchTag() throws ConditionThrowable
434    {
435        if (catchTags != NIL)
436            catchTags = catchTags.cdr();
437        else
438            Debug.assertTrue(false);
439    }
440
441    public void throwToTag(LispObject tag, LispObject result)
442        throws ConditionThrowable
443    {
444        LispObject rest = catchTags;
445        while (rest != NIL) {
446            if (rest.car() == tag)
447                throw new Throw(tag, result, this);
448            rest = rest.cdr();
449        }
450        error(new ControlError("Attempt to throw to the nonexistent tag " +
451                                tag.writeToString() + "."));
452    }
453
454
455    private StackFrame stack = null;
456
457    @Deprecated
458    public LispObject getStack()
459    {
460        return NIL;
461    }
462
463    @Deprecated
464    public void setStack(LispObject stack)
465    {
466    }
467
468    public final void pushStackFrame(StackFrame frame) 
469  throws ConditionThrowable
470    {
471  frame.setNext(stack);
472  stack = frame;
473    }
474
475
476    public final void popStackFrame()
477    {
478        if (stack != null)
479            stack = stack.getNext();
480    }
481
482    public void resetStack()
483    {
484        stack = null;
485    }
486
487    @Override
488    public LispObject execute(LispObject function) throws ConditionThrowable
489    {
490        if (use_fast_calls)
491            return function.execute();
492
493        pushStackFrame(new LispStackFrame(function));
494        try {
495            return function.execute();
496        }
497        finally {
498            popStackFrame();
499        }
500    }
501
502    @Override
503    public LispObject execute(LispObject function, LispObject arg)
504        throws ConditionThrowable
505    {
506        if (use_fast_calls)
507            return function.execute(arg);
508
509        pushStackFrame(new LispStackFrame(function, arg));
510        try {
511            return function.execute(arg);
512        }
513        finally {
514            popStackFrame();
515        }
516    }
517
518    @Override
519    public LispObject execute(LispObject function, LispObject first,
520                              LispObject second)
521        throws ConditionThrowable
522    {
523        if (use_fast_calls)
524            return function.execute(first, second);
525
526        pushStackFrame(new LispStackFrame(function, first, second));
527        try {
528            return function.execute(first, second);
529        }
530        finally {
531            popStackFrame();
532        }
533    }
534
535    @Override
536    public LispObject execute(LispObject function, LispObject first,
537                              LispObject second, LispObject third)
538        throws ConditionThrowable
539    {
540        if (use_fast_calls)
541            return function.execute(first, second, third);
542
543        pushStackFrame(new LispStackFrame(function, first, second, third));
544        try {
545            return function.execute(first, second, third);
546        }
547        finally {
548            popStackFrame();
549        }
550    }
551
552    @Override
553    public LispObject execute(LispObject function, LispObject first,
554                              LispObject second, LispObject third,
555                              LispObject fourth)
556        throws ConditionThrowable
557    {
558        if (use_fast_calls)
559            return function.execute(first, second, third, fourth);
560
561        pushStackFrame(new LispStackFrame(function, first, second, third, fourth));
562        try {
563            return function.execute(first, second, third, fourth);
564        }
565        finally {
566            popStackFrame();
567        }
568    }
569
570    @Override
571    public LispObject execute(LispObject function, LispObject first,
572                              LispObject second, LispObject third,
573                              LispObject fourth, LispObject fifth)
574        throws ConditionThrowable
575    {
576        if (use_fast_calls)
577            return function.execute(first, second, third, fourth, fifth);
578
579        pushStackFrame(new LispStackFrame(function, first, second, third, fourth, fifth));
580        try {
581            return function.execute(first, second, third, fourth, fifth);
582        }
583        finally {
584            popStackFrame();
585        }
586    }
587
588    @Override
589    public LispObject execute(LispObject function, LispObject first,
590                              LispObject second, LispObject third,
591                              LispObject fourth, LispObject fifth,
592                              LispObject sixth)
593        throws ConditionThrowable
594    {
595        if (use_fast_calls)
596            return function.execute(first, second, third, fourth, fifth, sixth);
597
598        pushStackFrame(new LispStackFrame(function, first, second, 
599            third, fourth, fifth, sixth));
600        try {
601            return function.execute(first, second, third, fourth, fifth, sixth);
602        }
603        finally {
604            popStackFrame();
605        }
606    }
607
608    @Override
609    public LispObject execute(LispObject function, LispObject first,
610                              LispObject second, LispObject third,
611                              LispObject fourth, LispObject fifth,
612                              LispObject sixth, LispObject seventh)
613        throws ConditionThrowable
614    {
615        if (use_fast_calls)
616            return function.execute(first, second, third, fourth, fifth, sixth,
617                                    seventh);
618
619        pushStackFrame(new LispStackFrame(function, first, second, third, 
620            fourth, fifth, sixth, seventh));
621        try {
622            return function.execute(first, second, third, fourth, fifth, sixth,
623                                    seventh);
624        }
625        finally {
626            popStackFrame();
627        }
628    }
629
630    public LispObject execute(LispObject function, LispObject first,
631                              LispObject second, LispObject third,
632                              LispObject fourth, LispObject fifth,
633                              LispObject sixth, LispObject seventh,
634                              LispObject eighth)
635        throws ConditionThrowable
636    {
637        if (use_fast_calls)
638            return function.execute(first, second, third, fourth, fifth, sixth,
639                                    seventh, eighth);
640
641        pushStackFrame(new LispStackFrame(function, first, second, third, 
642            fourth, fifth, sixth, seventh, eighth));
643        try {
644            return function.execute(first, second, third, fourth, fifth, sixth,
645                                    seventh, eighth);
646        }
647        finally {
648            popStackFrame();
649        }
650    }
651
652    public LispObject execute(LispObject function, LispObject[] args)
653        throws ConditionThrowable
654    {
655        if (use_fast_calls)
656            return function.execute(args);
657
658        pushStackFrame(new LispStackFrame(function, args));
659        try {
660            return function.execute(args);
661        }
662        finally {
663            popStackFrame();
664        }
665    }
666
667    public void printBacktrace()
668    {
669        printBacktrace(0);
670    }
671
672    public void printBacktrace(int limit)
673    {
674        if (stack != null) {
675            try {
676                int count = 0;
677                Stream out =
678                    checkCharacterOutputStream(Symbol.TRACE_OUTPUT.symbolValue());
679                out._writeLine("Evaluation stack:");
680                out._finishOutput();
681
682                StackFrame s = stack;
683                while (s != null) {
684                    out._writeString("  ");
685                    out._writeString(String.valueOf(count));
686                    out._writeString(": ");
687                   
688                    pprint(s.toLispList(), out.getCharPos(), out);
689                    out.terpri();
690                    out._finishOutput();
691                    if (limit > 0 && ++count == limit)
692                        break;
693                    s = s.next;
694                }
695            }
696            catch (Throwable t) {
697                t.printStackTrace();
698            }
699        }
700    }
701
702    public LispObject backtrace(int limit) throws ConditionThrowable
703    {
704        LispObject result = NIL;
705        if (stack != null) {
706            int count = 0;
707            try {
708                StackFrame s = stack;
709                while (s != null) {
710                    result = result.push(s);
711                    if (limit > 0 && ++count == limit)
712                        break;
713                    s = s.getNext();
714                }
715            }
716            catch (Throwable t) {
717                t.printStackTrace();
718            }
719        }
720        return result.nreverse();
721    }
722
723    public void incrementCallCounts() throws ConditionThrowable
724    {
725        StackFrame s = stack;
726
727        for (int i = 0; i < 8; i++) {
728            if (s == null)
729                break;
730      if (s instanceof LispStackFrame) {
731    LispObject operator = ((LispStackFrame)s).getOperator();
732    if (operator != null) {
733        operator.incrementHotCount();
734        operator.incrementCallCount();
735    }
736    s = s.getNext();
737      }
738        }
739
740        while (s != null) {
741      if (s instanceof LispStackFrame) {
742    LispObject operator = ((LispStackFrame)s).getOperator();
743    if (operator != null)
744        operator.incrementCallCount();
745      }
746      s = s.getNext();
747        }
748    }
749
750    private static void pprint(LispObject obj, int indentBy, Stream stream)
751        throws ConditionThrowable
752    {
753        if (stream.getCharPos() == 0) {
754            StringBuffer sb = new StringBuffer();
755            for (int i = 0; i < indentBy; i++)
756                sb.append(' ');
757            stream._writeString(sb.toString());
758        }
759        String raw = obj.writeToString();
760        if (stream.getCharPos() + raw.length() < 80) {
761            // It fits.
762            stream._writeString(raw);
763            return;
764        }
765        // Object doesn't fit.
766        if (obj instanceof Cons) {
767            try {
768                boolean newlineBefore = false;
769                LispObject[] array = obj.copyToArray();
770                if (array.length > 0) {
771                    LispObject first = array[0];
772                    if (first == Symbol.LET) {
773                        newlineBefore = true;
774                    }
775                }
776                int charPos = stream.getCharPos();
777                if (newlineBefore && charPos != indentBy) {
778                    stream.terpri();
779                    charPos = stream.getCharPos();
780                }
781                if (charPos < indentBy) {
782                    StringBuffer sb = new StringBuffer();
783                    for (int i = charPos; i < indentBy; i++)
784                        sb.append(' ');
785                    stream._writeString(sb.toString());
786                }
787                stream.print('(');
788                for (int i = 0; i < array.length; i++) {
789                    pprint(array[i], indentBy + 2, stream);
790                    if (i < array.length - 1)
791                        stream.print(' ');
792                }
793                stream.print(')');
794            }
795            catch (ConditionThrowable t) {
796                Debug.trace(t);
797            }
798        } else {
799            stream.terpri();
800            StringBuffer sb = new StringBuffer();
801            for (int i = 0; i < indentBy; i++)
802                sb.append(' ');
803            stream._writeString(sb.toString());
804            stream._writeString(raw);
805            return;
806        }
807    }
808
809    @Override
810    public String writeToString() throws ConditionThrowable
811    {
812        StringBuffer sb = new StringBuffer("THREAD");
813        if (name != NIL) {
814            sb.append(" \"");
815            sb.append(name.getStringValue());
816            sb.append("\"");
817        }
818        return unreadableString(sb.toString());
819    }
820
821    // ### make-thread
822    private static final Primitive MAKE_THREAD =
823        new Primitive("make-thread", PACKAGE_THREADS, true, "function &key name")
824    {
825        @Override
826        public LispObject execute(LispObject[] args) throws ConditionThrowable
827        {
828            final int length = args.length;
829            if (length == 0)
830                error(new WrongNumberOfArgumentsException(this));
831            LispObject name = NIL;
832            if (length > 1) {
833                if ((length - 1) % 2 != 0)
834                    error(new ProgramError("Odd number of keyword arguments."));
835                if (length > 3)
836                    error(new WrongNumberOfArgumentsException(this));
837                if (args[1] == Keyword.NAME)
838                    name = args[2].STRING();
839                else
840                    error(new ProgramError("Unrecognized keyword argument " +
841                                            args[1].writeToString() + "."));
842            }
843            return new LispThread(checkFunction(args[0]), name);
844        }
845    };
846
847    // ### threadp
848    private static final Primitive THREADP =
849        new Primitive("threadp", PACKAGE_THREADS, true, "object",
850          "Boolean predicate as whether OBJECT is a thread.")
851    {
852        @Override
853        public LispObject execute(LispObject arg) throws ConditionThrowable
854        {
855            return arg instanceof LispThread ? T : NIL;
856        }
857    };
858
859    // ### thread-alive-p
860    private static final Primitive THREAD_ALIVE_P =
861        new Primitive("thread-alive-p", PACKAGE_THREADS, true, "thread",
862          "Boolean predicate whether THREAD is alive.")
863    {
864        @Override
865        public LispObject execute(LispObject arg) throws ConditionThrowable
866        {
867            final LispThread lispThread;
868            if (arg instanceof LispThread) {
869                lispThread = (LispThread) arg;
870            }
871            else {
872                return type_error(arg, Symbol.THREAD);
873            }
874            return lispThread.javaThread.isAlive() ? T : NIL;
875        }
876    };
877
878    // ### thread-name
879    private static final Primitive THREAD_NAME =
880        new Primitive("thread-name", PACKAGE_THREADS, true, "thread",
881          "Return the name of THREAD if it has one.")
882    {
883        @Override
884        public LispObject execute(LispObject arg) throws ConditionThrowable
885        {
886                if (arg instanceof LispThread) {
887                return ((LispThread)arg).name;
888            }
889                 return type_error(arg, Symbol.THREAD);
890        }
891    };
892
893    public static final long javaSleepInterval(LispObject lispSleep)
894            throws ConditionThrowable
895    {
896        double d =
897            checkDoubleFloat(lispSleep.multiplyBy(new DoubleFloat(1000))).getValue();
898        if (d < 0)
899            type_error(lispSleep, list(Symbol.REAL, Fixnum.ZERO));
900
901        return (d < Long.MAX_VALUE ? (long) d : Long.MAX_VALUE);
902    }
903
904    // ### sleep
905    private static final Primitive SLEEP = new Primitive("sleep", PACKAGE_CL, true, "seconds",
906               "Causes the invoking thread to sleep for SECONDS seconds.\nSECONDS may be a value between 0 1and 1.")
907    {
908        @Override
909        public LispObject execute(LispObject arg) throws ConditionThrowable
910        {
911
912            try {
913                Thread.sleep(javaSleepInterval(arg));
914            }
915            catch (InterruptedException e) {
916                currentThread().processThreadInterrupts();
917            }
918            return NIL;
919        }
920    };
921
922    // ### mapcar-threads
923    private static final Primitive MAPCAR_THREADS =
924        new Primitive("mapcar-threads", PACKAGE_THREADS, true, "function",
925          "Applies FUNCTION to all existing threads.")
926    {
927        @Override
928        public LispObject execute(LispObject arg) throws ConditionThrowable
929        {
930            Function fun = checkFunction(arg);
931            final LispThread thread = LispThread.currentThread();
932            LispObject result = NIL;
933            Iterator it = map.values().iterator();
934            while (it.hasNext()) {
935                LispObject[] args = new LispObject[1];
936                args[0] = (LispThread) it.next();
937                result = new Cons(funcall(fun, args, thread), result);
938            }
939            return result;
940        }
941    };
942
943    // ### destroy-thread
944    private static final Primitive DESTROY_THREAD =
945        new Primitive("destroy-thread", PACKAGE_THREADS, true, "thread", 
946          "Mark THREAD as destroyed.")
947    {
948        @Override
949        public LispObject execute(LispObject arg) throws ConditionThrowable
950        {
951            final LispThread thread;
952            if (arg instanceof LispThread) {
953                thread = (LispThread) arg;
954            }
955            else {
956                return type_error(arg, Symbol.THREAD);
957            }
958            thread.setDestroyed(true);
959            return T;
960        }
961    };
962
963    // ### interrupt-thread thread function &rest args => T
964    // Interrupts thread and forces it to apply function to args. When the
965    // function returns, the thread's original computation continues. If
966    // multiple interrupts are queued for a thread, they are all run, but the
967    // order is not guaranteed.
968    private static final Primitive INTERRUPT_THREAD =
969        new Primitive("interrupt-thread", PACKAGE_THREADS, true,
970          "thread function &rest args",
971          "Interrupts THREAD and forces it to apply FUNCTION to ARGS.\nWhen the function returns, the thread's original computation continues. If  multiple interrupts are queued for a thread, they are all run, but the order is not guaranteed.")
972    {
973        @Override
974        public LispObject execute(LispObject[] args) throws ConditionThrowable
975        {
976            if (args.length < 2)
977                return error(new WrongNumberOfArgumentsException(this));
978            final LispThread thread;
979            if (args[0] instanceof LispThread) {
980                thread = (LispThread) args[0];
981            }
982            else {
983                return type_error(args[0], Symbol.THREAD);
984            }
985            LispObject fun = args[1];
986            LispObject funArgs = NIL;
987            for (int i = args.length; i-- > 2;)
988                funArgs = new Cons(args[i], funArgs);
989            thread.interrupt(fun, funArgs);
990            return T;
991        }
992    };
993
994    // ### current-thread
995    private static final Primitive CURRENT_THREAD =
996        new Primitive("current-thread", PACKAGE_THREADS, true, "",
997          "Returns a reference to invoking thread.")
998    {
999        @Override
1000        public LispObject execute() throws ConditionThrowable
1001        {
1002            return currentThread();
1003        }
1004    };
1005
1006    // ### backtrace
1007    private static final Primitive BACKTRACE =
1008        new Primitive("backtrace", PACKAGE_SYS, true, "",
1009          "Returns a backtrace of the invoking thread.")
1010    {
1011        @Override
1012        public LispObject execute(LispObject[] args)
1013            throws ConditionThrowable
1014        {
1015            if (args.length > 1)
1016                return error(new WrongNumberOfArgumentsException(this));
1017            int limit = args.length > 0 ? Fixnum.getValue(args[0]) : 0;
1018            return currentThread().backtrace(limit);
1019        }
1020    };
1021    // ### frame-to-string
1022    private static final Primitive FRAME_TO_STRING =
1023        new Primitive("frame-to-string", PACKAGE_SYS, true, "frame")
1024    {
1025        @Override
1026        public LispObject execute(LispObject[] args)
1027            throws ConditionThrowable
1028        {
1029            if (args.length != 1)
1030                return error(new WrongNumberOfArgumentsException(this));
1031           
1032            return checkStackFrame(args[0]).toLispString();
1033        }
1034    };
1035
1036    // ### frame-to-list
1037    private static final Primitive FRAME_TO_LIST =
1038        new Primitive("frame-to-list", PACKAGE_SYS, true, "frame")
1039    {
1040        @Override
1041        public LispObject execute(LispObject[] args)
1042            throws ConditionThrowable
1043        {
1044            if (args.length != 1)
1045                return error(new WrongNumberOfArgumentsException(this));
1046
1047            return checkStackFrame(args[0]).toLispList();
1048        }
1049    };
1050
1051
1052    static {
1053        //FIXME: this block has been added for pre-0.16 compatibility
1054        // and can be removed the latest at release 0.22
1055        try {
1056            PACKAGE_EXT.export(Symbol.intern("MAKE-THREAD", PACKAGE_THREADS));
1057            PACKAGE_EXT.export(Symbol.intern("THREADP", PACKAGE_THREADS));
1058            PACKAGE_EXT.export(Symbol.intern("THREAD-ALIVE-P", PACKAGE_THREADS));
1059            PACKAGE_EXT.export(Symbol.intern("THREAD-NAME", PACKAGE_THREADS));
1060            PACKAGE_EXT.export(Symbol.intern("MAPCAR-THREADS", PACKAGE_THREADS));
1061            PACKAGE_EXT.export(Symbol.intern("DESTROY-THREAD", PACKAGE_THREADS));
1062            PACKAGE_EXT.export(Symbol.intern("INTERRUPT-THREAD", PACKAGE_THREADS));
1063            PACKAGE_EXT.export(Symbol.intern("CURRENT-THREAD", PACKAGE_THREADS));
1064        }
1065        catch (ConditionThrowable ct) { }
1066    }
1067
1068    // ### use-fast-calls
1069    private static final Primitive USE_FAST_CALLS =
1070        new Primitive("use-fast-calls", PACKAGE_SYS, true)
1071    {
1072        @Override
1073        public LispObject execute(LispObject arg) throws ConditionThrowable
1074        {
1075            use_fast_calls = (arg != NIL);
1076            return use_fast_calls ? T : NIL;
1077        }
1078    };
1079
1080    // ### synchronized-on
1081    private static final SpecialOperator SYNCHRONIZED_ON =
1082        new SpecialOperator("synchronized-on", PACKAGE_THREADS, true,
1083                            "form &body body")
1084    {
1085        @Override
1086        public LispObject execute(LispObject args, Environment env)
1087            throws ConditionThrowable
1088        {
1089          if (args == NIL)
1090            return error(new WrongNumberOfArgumentsException(this));
1091
1092          LispThread thread = LispThread.currentThread();
1093          synchronized (eval(args.car(), env, thread).lockableInstance()) {
1094              return progn(args.cdr(), env, thread);
1095          }
1096        }
1097    };
1098
1099    // ### object-wait
1100    private static final Primitive OBJECT_WAIT =
1101        new Primitive("object-wait", PACKAGE_THREADS, true,
1102                      "object &optional timeout")
1103    {
1104        @Override
1105        public LispObject execute(LispObject object)
1106            throws ConditionThrowable
1107        {
1108            try {
1109                object.lockableInstance().wait();
1110            }
1111            catch (InterruptedException e) {
1112                currentThread().processThreadInterrupts();
1113            }
1114            catch (IllegalMonitorStateException e) {
1115                return error(new IllegalMonitorState());
1116            }
1117            return NIL;
1118        }
1119
1120        @Override
1121        public LispObject execute(LispObject object, LispObject timeout)
1122            throws ConditionThrowable
1123        {
1124            try {
1125                object.lockableInstance().wait(javaSleepInterval(timeout));
1126            }
1127            catch (InterruptedException e) {
1128                currentThread().processThreadInterrupts();
1129            }
1130            catch (IllegalMonitorStateException e) {
1131                return error(new IllegalMonitorState());
1132            }
1133            return NIL;
1134        }
1135    };
1136
1137    // ### object-notify
1138    private static final Primitive OBJECT_NOTIFY =
1139        new Primitive("object-notify", PACKAGE_THREADS, true,
1140                      "object")
1141    {
1142        @Override
1143        public LispObject execute(LispObject object)
1144            throws ConditionThrowable
1145        {
1146            try {
1147                object.lockableInstance().notify();
1148            }
1149            catch (IllegalMonitorStateException e) {
1150                return error(new IllegalMonitorState());
1151            }
1152            return NIL;
1153        }
1154    };
1155
1156    // ### object-notify-all
1157    private static final Primitive OBJECT_NOTIFY_ALL =
1158        new Primitive("object-notify-all", PACKAGE_THREADS, true,
1159                      "object")
1160    {
1161        @Override
1162        public LispObject execute(LispObject object)
1163            throws ConditionThrowable
1164        {
1165            try {
1166                object.lockableInstance().notifyAll();
1167            }
1168            catch (IllegalMonitorStateException e) {
1169                return error(new IllegalMonitorState());
1170            }
1171            return NIL;
1172        }
1173    };
1174
1175
1176}
Note: See TracBrowser for help on using the repository browser.