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

Last change on this file was 12826, checked in by vvoutilainen, 14 years ago

DocString? annotation support, for generating DOCUMENTATION, and
later Javadoc from the same data. Also includes TAGS support
for the DocString? annotations. Patch by Matt Seddon.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 37.3 KB
Line 
1/*
2 * LispThread.java
3 *
4 * Copyright (C) 2003-2007 Peter Graves
5 * $Id: LispThread.java 12826 2010-07-25 19:09:13Z vvoutilainen $
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    @Deprecated
516    public LispObject getStack()
517    {
518        return NIL;
519    }
520
521    @Deprecated
522    public void setStack(LispObject stack)
523    {
524    }
525
526    public final void pushStackFrame(StackFrame frame)
527    {
528  frame.setNext(stack);
529  stack = frame;
530    }
531
532
533    public final void popStackFrame()
534    {
535        if (stack != null)
536            stack = stack.getNext();
537    }
538
539    public void resetStack()
540    {
541        stack = null;
542    }
543
544    @Override
545    public LispObject execute(LispObject function)
546    {
547        if (use_fast_calls)
548            return function.execute();
549
550        pushStackFrame(new LispStackFrame(function));
551        try {
552            return function.execute();
553        }
554        finally {
555            popStackFrame();
556        }
557    }
558
559    @Override
560    public LispObject execute(LispObject function, LispObject arg)
561
562    {
563        if (use_fast_calls)
564            return function.execute(arg);
565
566        pushStackFrame(new LispStackFrame(function, arg));
567        try {
568            return function.execute(arg);
569        }
570        finally {
571            popStackFrame();
572        }
573    }
574
575    @Override
576    public LispObject execute(LispObject function, LispObject first,
577                              LispObject second)
578
579    {
580        if (use_fast_calls)
581            return function.execute(first, second);
582
583        pushStackFrame(new LispStackFrame(function, first, second));
584        try {
585            return function.execute(first, second);
586        }
587        finally {
588            popStackFrame();
589        }
590    }
591
592    @Override
593    public LispObject execute(LispObject function, LispObject first,
594                              LispObject second, LispObject third)
595
596    {
597        if (use_fast_calls)
598            return function.execute(first, second, third);
599
600        pushStackFrame(new LispStackFrame(function, first, second, third));
601        try {
602            return function.execute(first, second, third);
603        }
604        finally {
605            popStackFrame();
606        }
607    }
608
609    @Override
610    public LispObject execute(LispObject function, LispObject first,
611                              LispObject second, LispObject third,
612                              LispObject fourth)
613
614    {
615        if (use_fast_calls)
616            return function.execute(first, second, third, fourth);
617
618        pushStackFrame(new LispStackFrame(function, first, second, third, fourth));
619        try {
620            return function.execute(first, second, third, fourth);
621        }
622        finally {
623            popStackFrame();
624        }
625    }
626
627    @Override
628    public LispObject execute(LispObject function, LispObject first,
629                              LispObject second, LispObject third,
630                              LispObject fourth, LispObject fifth)
631
632    {
633        if (use_fast_calls)
634            return function.execute(first, second, third, fourth, fifth);
635
636        pushStackFrame(new LispStackFrame(function, first, second, third, fourth, fifth));
637        try {
638            return function.execute(first, second, third, fourth, fifth);
639        }
640        finally {
641            popStackFrame();
642        }
643    }
644
645    @Override
646    public LispObject execute(LispObject function, LispObject first,
647                              LispObject second, LispObject third,
648                              LispObject fourth, LispObject fifth,
649                              LispObject sixth)
650
651    {
652        if (use_fast_calls)
653            return function.execute(first, second, third, fourth, fifth, sixth);
654
655        pushStackFrame(new LispStackFrame(function, first, second, 
656            third, fourth, fifth, sixth));
657        try {
658            return function.execute(first, second, third, fourth, fifth, sixth);
659        }
660        finally {
661            popStackFrame();
662        }
663    }
664
665    @Override
666    public LispObject execute(LispObject function, LispObject first,
667                              LispObject second, LispObject third,
668                              LispObject fourth, LispObject fifth,
669                              LispObject sixth, LispObject seventh)
670
671    {
672        if (use_fast_calls)
673            return function.execute(first, second, third, fourth, fifth, sixth,
674                                    seventh);
675
676        pushStackFrame(new LispStackFrame(function, first, second, third, 
677            fourth, fifth, sixth, seventh));
678        try {
679            return function.execute(first, second, third, fourth, fifth, sixth,
680                                    seventh);
681        }
682        finally {
683            popStackFrame();
684        }
685    }
686
687    public LispObject execute(LispObject function, LispObject first,
688                              LispObject second, LispObject third,
689                              LispObject fourth, LispObject fifth,
690                              LispObject sixth, LispObject seventh,
691                              LispObject eighth)
692
693    {
694        if (use_fast_calls)
695            return function.execute(first, second, third, fourth, fifth, sixth,
696                                    seventh, eighth);
697
698        pushStackFrame(new LispStackFrame(function, first, second, third, 
699            fourth, fifth, sixth, seventh, eighth));
700        try {
701            return function.execute(first, second, third, fourth, fifth, sixth,
702                                    seventh, eighth);
703        }
704        finally {
705            popStackFrame();
706        }
707    }
708
709    public LispObject execute(LispObject function, LispObject[] args)
710
711    {
712        if (use_fast_calls)
713            return function.execute(args);
714
715        pushStackFrame(new LispStackFrame(function, args));
716        try {
717            return function.execute(args);
718        }
719        finally {
720            popStackFrame();
721        }
722    }
723
724    public void printBacktrace()
725    {
726        printBacktrace(0);
727    }
728
729    public void printBacktrace(int limit)
730    {
731        if (stack != null) {
732            int count = 0;
733            Stream out =
734                checkCharacterOutputStream(Symbol.TRACE_OUTPUT.symbolValue());
735            out._writeLine("Evaluation stack:");
736            out._finishOutput();
737
738            StackFrame s = stack;
739            while (s != null) {
740                out._writeString("  ");
741                out._writeString(String.valueOf(count));
742                out._writeString(": ");
743
744                pprint(s.toLispList(), out.getCharPos(), out);
745                out.terpri();
746                out._finishOutput();
747                if (limit > 0 && ++count == limit)
748                    break;
749                s = s.next;
750            }
751        }
752    }
753
754    public LispObject backtrace(int limit)
755    {
756        LispObject result = NIL;
757        if (stack != null) {
758            int count = 0;
759            StackFrame s = stack;
760            while (s != null) {
761                result = result.push(s);
762                if (limit > 0 && ++count == limit)
763                    break;
764                s = s.getNext();
765            }
766        }
767        return result.nreverse();
768    }
769
770    public void incrementCallCounts()
771    {
772        StackFrame s = stack;
773
774        for (int i = 0; i < 8; i++) {
775            if (s == null)
776                break;
777      if (s instanceof LispStackFrame) {
778    LispObject operator = ((LispStackFrame)s).getOperator();
779    if (operator != null) {
780        operator.incrementHotCount();
781        operator.incrementCallCount();
782    }
783    s = s.getNext();
784      }
785        }
786
787        while (s != null) {
788      if (s instanceof LispStackFrame) {
789    LispObject operator = ((LispStackFrame)s).getOperator();
790    if (operator != null)
791        operator.incrementCallCount();
792      }
793      s = s.getNext();
794        }
795    }
796
797    private static void pprint(LispObject obj, int indentBy, Stream stream)
798
799    {
800        if (stream.getCharPos() == 0) {
801            StringBuffer sb = new StringBuffer();
802            for (int i = 0; i < indentBy; i++)
803                sb.append(' ');
804            stream._writeString(sb.toString());
805        }
806        String raw = obj.writeToString();
807        if (stream.getCharPos() + raw.length() < 80) {
808            // It fits.
809            stream._writeString(raw);
810            return;
811        }
812        // Object doesn't fit.
813        if (obj instanceof Cons) {
814            boolean newlineBefore = false;
815            LispObject[] array = obj.copyToArray();
816            if (array.length > 0) {
817                LispObject first = array[0];
818                if (first == Symbol.LET) {
819                    newlineBefore = true;
820                }
821            }
822            int charPos = stream.getCharPos();
823            if (newlineBefore && charPos != indentBy) {
824                stream.terpri();
825                charPos = stream.getCharPos();
826            }
827            if (charPos < indentBy) {
828                StringBuffer sb = new StringBuffer();
829                for (int i = charPos; i < indentBy; i++)
830                    sb.append(' ');
831                stream._writeString(sb.toString());
832            }
833            stream.print('(');
834            for (int i = 0; i < array.length; i++) {
835                pprint(array[i], indentBy + 2, stream);
836                if (i < array.length - 1)
837                   stream.print(' ');
838            }
839            stream.print(')');
840        } else {
841            stream.terpri();
842            StringBuffer sb = new StringBuffer();
843            for (int i = 0; i < indentBy; i++)
844                sb.append(' ');
845            stream._writeString(sb.toString());
846            stream._writeString(raw);
847            return;
848        }
849    }
850
851    @Override
852    public String writeToString()
853    {
854        StringBuffer sb = new StringBuffer("THREAD");
855        if (name != NIL) {
856            sb.append(" \"");
857            sb.append(name.getStringValue());
858            sb.append("\"");
859        }
860        return unreadableString(sb.toString());
861    }
862
863    @DocString(name="make-thread", args="function &optional &key name")
864    private static final Primitive MAKE_THREAD =
865        new Primitive("make-thread", PACKAGE_THREADS, true, "function &optional &key name")
866    {
867        @Override
868        public LispObject execute(LispObject[] args)
869        {
870            final int length = args.length;
871            if (length == 0)
872                error(new WrongNumberOfArgumentsException(this));
873            LispObject name = NIL;
874            if (length > 1) {
875                if ((length - 1) % 2 != 0)
876                    error(new ProgramError("Odd number of keyword arguments."));
877                if (length > 3)
878                    error(new WrongNumberOfArgumentsException(this));
879                if (args[1] == Keyword.NAME)
880                    name = args[2].STRING();
881                else
882                    error(new ProgramError("Unrecognized keyword argument " +
883                                            args[1].writeToString() + "."));
884            }
885            return new LispThread(checkFunction(args[0]), name);
886        }
887    };
888
889    @DocString(name="threadp", args="object",
890    doc="Boolean predicate testing if OBJECT is a thread.")
891    private static final Primitive THREADP =
892        new Primitive("threadp", PACKAGE_THREADS, true)
893    {
894        @Override
895        public LispObject execute(LispObject arg)
896        {
897            return arg instanceof LispThread ? T : NIL;
898        }
899    };
900
901    @DocString(name="thread-alive-p", args="thread",
902    doc="Returns T if THREAD is alive.")
903    private static final Primitive THREAD_ALIVE_P =
904        new Primitive("thread-alive-p", PACKAGE_THREADS, true, "thread",
905          "Boolean predicate whether THREAD is alive.")
906    {
907        @Override
908        public LispObject execute(LispObject arg)
909        {
910            final LispThread lispThread;
911            if (arg instanceof LispThread) {
912                lispThread = (LispThread) arg;
913            }
914            else {
915                return type_error(arg, Symbol.THREAD);
916            }
917            return lispThread.javaThread.isAlive() ? T : NIL;
918        }
919    };
920
921    @DocString(name="thread-name", args="thread",
922    doc="Return the name of THREAD, if it has one.")
923    private static final Primitive THREAD_NAME =
924        new Primitive("thread-name", PACKAGE_THREADS, true)
925    {
926        @Override
927        public LispObject execute(LispObject arg)
928        {
929                if (arg instanceof LispThread) {
930                return ((LispThread)arg).name;
931            }
932                 return type_error(arg, Symbol.THREAD);
933        }
934    };
935
936    private static final Primitive THREAD_JOIN =
937        new Primitive("thread-join", PACKAGE_THREADS, true, "thread",
938                      "Waits for thread to finish.")
939    {
940        @Override
941        public LispObject execute(LispObject arg)
942        {
943            // join the thread, and returns it's value.  The second return
944            // value is T if the thread finishes normally, NIL if its
945            // interrupted.
946            if (arg instanceof LispThread) {               
947                final LispThread joinedThread = (LispThread) arg;
948                final LispThread waitingThread = currentThread();
949                try {
950                    joinedThread.javaThread.join();
951                    return 
952                        waitingThread.setValues(joinedThread.threadValue, T);
953                } catch (InterruptedException e) {
954                    waitingThread.processThreadInterrupts();
955                    return 
956                        waitingThread.setValues(joinedThread.threadValue, NIL);
957                }
958            } else {
959                return type_error(arg, Symbol.THREAD);
960            } 
961        }
962    };
963
964
965    public static final long javaSleepInterval(LispObject lispSleep)
966
967    {
968        double d =
969            checkDoubleFloat(lispSleep.multiplyBy(new DoubleFloat(1000))).getValue();
970        if (d < 0)
971            type_error(lispSleep, list(Symbol.REAL, Fixnum.ZERO));
972
973        return (d < Long.MAX_VALUE ? (long) d : Long.MAX_VALUE);
974    }
975
976    @DocString(name="sleep", args="seconds",
977    doc="Causes the invoking thread to sleep for SECONDS seconds.\n"+
978        "SECONDS may be a value between 0 1and 1.")
979    private static final Primitive SLEEP = new Primitive("sleep", PACKAGE_CL, true)
980    {
981        @Override
982        public LispObject execute(LispObject arg)
983        {
984
985            try {
986                Thread.sleep(javaSleepInterval(arg));
987            }
988            catch (InterruptedException e) {
989                currentThread().processThreadInterrupts();
990            }
991            return NIL;
992        }
993    };
994
995    @DocString(name="mapcar-threads", args= "function",
996    doc="Applies FUNCTION to all existing threads.")
997    private static final Primitive MAPCAR_THREADS =
998        new Primitive("mapcar-threads", PACKAGE_THREADS, true)
999    {
1000        @Override
1001        public LispObject execute(LispObject arg)
1002        {
1003            Function fun = checkFunction(arg);
1004            final LispThread thread = LispThread.currentThread();
1005            LispObject result = NIL;
1006            Iterator it = map.values().iterator();
1007            while (it.hasNext()) {
1008                LispObject[] args = new LispObject[1];
1009                args[0] = (LispThread) it.next();
1010                result = new Cons(funcall(fun, args, thread), result);
1011            }
1012            return result;
1013        }
1014    };
1015
1016    @DocString(name="destroy-thread", args="thread", doc="Mark THREAD as destroyed")
1017    private static final Primitive DESTROY_THREAD =
1018        new Primitive("destroy-thread", PACKAGE_THREADS, true)
1019    {
1020        @Override
1021        public LispObject execute(LispObject arg)
1022        {
1023            final LispThread thread;
1024            if (arg instanceof LispThread) {
1025                thread = (LispThread) arg;
1026            }
1027            else {
1028                return type_error(arg, Symbol.THREAD);
1029            }
1030            thread.setDestroyed(true);
1031            return T;
1032        }
1033    };
1034
1035    // => T
1036    @DocString(name="interrupt-thread", args="thread function &rest args",
1037    doc="Interrupts thread and forces it to apply function to args. When the\n"+
1038        "function returns, the thread's original computation continues. If\n"+
1039        "multiple interrupts are queued for a thread, they are all run, but the\n"+
1040        "order is not guaranteed.")
1041    private static final Primitive INTERRUPT_THREAD =
1042        new Primitive("interrupt-thread", PACKAGE_THREADS, true,
1043          "thread function &rest args",
1044          "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.")
1045    {
1046        @Override
1047        public LispObject execute(LispObject[] args)
1048        {
1049            if (args.length < 2)
1050                return error(new WrongNumberOfArgumentsException(this));
1051            final LispThread thread;
1052            if (args[0] instanceof LispThread) {
1053                thread = (LispThread) args[0];
1054            }
1055            else {
1056                return type_error(args[0], Symbol.THREAD);
1057            }
1058            LispObject fun = args[1];
1059            LispObject funArgs = NIL;
1060            for (int i = args.length; i-- > 2;)
1061                funArgs = new Cons(args[i], funArgs);
1062            thread.interrupt(fun, funArgs);
1063            return T;
1064        }
1065    };
1066
1067    @DocString(name="current-thread",
1068    doc="Returns a reference to invoking thread.")
1069    private static final Primitive CURRENT_THREAD =
1070        new Primitive("current-thread", PACKAGE_THREADS, true)
1071    {
1072        @Override
1073        public LispObject execute()
1074        {
1075            return currentThread();
1076        }
1077    };
1078
1079    @DocString(name="backtrace",
1080               doc="Returns a backtrace of the invoking thread.")
1081    private static final Primitive BACKTRACE =
1082        new Primitive("backtrace", PACKAGE_SYS, true)
1083    {
1084        @Override
1085        public LispObject execute(LispObject[] args)
1086
1087        {
1088            if (args.length > 1)
1089                return error(new WrongNumberOfArgumentsException(this));
1090            int limit = args.length > 0 ? Fixnum.getValue(args[0]) : 0;
1091            return currentThread().backtrace(limit);
1092        }
1093    };
1094    @DocString(name="frame-to-string", args="frame")
1095    private static final Primitive FRAME_TO_STRING =
1096        new Primitive("frame-to-string", PACKAGE_SYS, true)
1097    {
1098        @Override
1099        public LispObject execute(LispObject[] args)
1100
1101        {
1102            if (args.length != 1)
1103                return error(new WrongNumberOfArgumentsException(this));
1104           
1105            return checkStackFrame(args[0]).toLispString();
1106        }
1107    };
1108
1109    @DocString(name="frame-to-list", args="frame")
1110    private static final Primitive FRAME_TO_LIST =
1111        new Primitive("frame-to-list", PACKAGE_SYS, true)
1112    {
1113        @Override
1114        public LispObject execute(LispObject[] args)
1115
1116        {
1117            if (args.length != 1)
1118                return error(new WrongNumberOfArgumentsException(this));
1119
1120            return checkStackFrame(args[0]).toLispList();
1121        }
1122    };
1123
1124
1125    @DocString(name="use-fast-calls")
1126    private static final Primitive USE_FAST_CALLS =
1127        new Primitive("use-fast-calls", PACKAGE_SYS, true)
1128    {
1129        @Override
1130        public LispObject execute(LispObject arg)
1131        {
1132            use_fast_calls = (arg != NIL);
1133            return use_fast_calls ? T : NIL;
1134        }
1135    };
1136
1137    @DocString(name="synchronized-on", args="form &body body")
1138    private static final SpecialOperator SYNCHRONIZED_ON =
1139        new SpecialOperator("synchronized-on", PACKAGE_THREADS, true,
1140                            "form &body body")
1141    {
1142        @Override
1143        public LispObject execute(LispObject args, Environment env)
1144
1145        {
1146          if (args == NIL)
1147            return error(new WrongNumberOfArgumentsException(this));
1148
1149          LispThread thread = LispThread.currentThread();
1150          synchronized (eval(args.car(), env, thread).lockableInstance()) {
1151              return progn(args.cdr(), env, thread);
1152          }
1153        }
1154    };
1155
1156    @DocString(name="object-wait", args="object &optional timeout")
1157    private static final Primitive OBJECT_WAIT =
1158        new Primitive("object-wait", PACKAGE_THREADS, true)
1159    {
1160        @Override
1161        public LispObject execute(LispObject object)
1162
1163        {
1164            try {
1165                object.lockableInstance().wait();
1166            }
1167            catch (InterruptedException e) {
1168                currentThread().processThreadInterrupts();
1169            }
1170            catch (IllegalMonitorStateException e) {
1171                return error(new IllegalMonitorState());
1172            }
1173            return NIL;
1174        }
1175
1176        @Override
1177        public LispObject execute(LispObject object, LispObject timeout)
1178
1179        {
1180            try {
1181                object.lockableInstance().wait(javaSleepInterval(timeout));
1182            }
1183            catch (InterruptedException e) {
1184                currentThread().processThreadInterrupts();
1185            }
1186            catch (IllegalMonitorStateException e) {
1187                return error(new IllegalMonitorState());
1188            }
1189            return NIL;
1190        }
1191    };
1192
1193    @DocString(name="object-notify", args="object")
1194    private static final Primitive OBJECT_NOTIFY =
1195        new Primitive("object-notify", PACKAGE_THREADS, true,
1196                      "object")
1197    {
1198        @Override
1199        public LispObject execute(LispObject object)
1200
1201        {
1202            try {
1203                object.lockableInstance().notify();
1204            }
1205            catch (IllegalMonitorStateException e) {
1206                return error(new IllegalMonitorState());
1207            }
1208            return NIL;
1209        }
1210    };
1211
1212    @DocString(name="object-notify-all", args="object")
1213    private static final Primitive OBJECT_NOTIFY_ALL =
1214        new Primitive("object-notify-all", PACKAGE_THREADS, true)
1215    {
1216        @Override
1217        public LispObject execute(LispObject object)
1218
1219        {
1220            try {
1221                object.lockableInstance().notifyAll();
1222            }
1223            catch (IllegalMonitorStateException e) {
1224                return error(new IllegalMonitorState());
1225            }
1226            return NIL;
1227        }
1228    };
1229
1230
1231}
Note: See TracBrowser for help on using the repository browser.