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

Last change on this file was 13109, checked in by Mark Evenson, 15 years ago

Remove the deprecated and dangerously non-functional getStack()/setStack() methods.

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