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

Last change on this file was 12634, checked in by ehuelsmann, 15 years ago

Implement THREADS:THREAD-JOIN.

Patch by: David Kirkman dkirkman _at_ ucsd dot com.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 37.6 KB
Line 
1/*
2 * LispThread.java
3 *
4 * Copyright (C) 2003-2007 Peter Graves
5 * $Id: LispThread.java 12634 2010-04-24 22:31:36Z ehuelsmann $
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    // ### make-thread
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    // ### threadp
890    private static final Primitive THREADP =
891        new Primitive("threadp", PACKAGE_THREADS, true, "object",
892          "Boolean predicate as whether OBJECT is a thread.")
893    {
894        @Override
895        public LispObject execute(LispObject arg)
896        {
897            return arg instanceof LispThread ? T : NIL;
898        }
899    };
900
901    // ### thread-alive-p
902    private static final Primitive THREAD_ALIVE_P =
903        new Primitive("thread-alive-p", PACKAGE_THREADS, true, "thread",
904          "Boolean predicate whether THREAD is alive.")
905    {
906        @Override
907        public LispObject execute(LispObject arg)
908        {
909            final LispThread lispThread;
910            if (arg instanceof LispThread) {
911                lispThread = (LispThread) arg;
912            }
913            else {
914                return type_error(arg, Symbol.THREAD);
915            }
916            return lispThread.javaThread.isAlive() ? T : NIL;
917        }
918    };
919
920    // ### thread-name
921    private static final Primitive THREAD_NAME =
922        new Primitive("thread-name", PACKAGE_THREADS, true, "thread",
923          "Return the name of THREAD if it has one.")
924    {
925        @Override
926        public LispObject execute(LispObject arg)
927        {
928                if (arg instanceof LispThread) {
929                return ((LispThread)arg).name;
930            }
931                 return type_error(arg, Symbol.THREAD);
932        }
933    };
934
935    private static final Primitive THREAD_JOIN =
936        new Primitive("thread-join", PACKAGE_THREADS, true, "thread",
937                      "Waits for thread to finish.")
938    {
939        @Override
940        public LispObject execute(LispObject arg)
941        {
942            // join the thread, and returns it's value.  The second return
943            // value is T if the thread finishes normally, NIL if its
944            // interrupted.
945            if (arg instanceof LispThread) {               
946                final LispThread joinedThread = (LispThread) arg;
947                final LispThread waitingThread = currentThread();
948                try {
949                    joinedThread.javaThread.join();
950                    return 
951                        waitingThread.setValues(joinedThread.threadValue, T);
952                } catch (InterruptedException e) {
953                    waitingThread.processThreadInterrupts();
954                    return 
955                        waitingThread.setValues(joinedThread.threadValue, NIL);
956                }
957            } else {
958                return type_error(arg, Symbol.THREAD);
959            } 
960        }
961    };
962
963
964    public static final long javaSleepInterval(LispObject lispSleep)
965
966    {
967        double d =
968            checkDoubleFloat(lispSleep.multiplyBy(new DoubleFloat(1000))).getValue();
969        if (d < 0)
970            type_error(lispSleep, list(Symbol.REAL, Fixnum.ZERO));
971
972        return (d < Long.MAX_VALUE ? (long) d : Long.MAX_VALUE);
973    }
974
975    // ### sleep
976    private static final Primitive SLEEP = new Primitive("sleep", PACKAGE_CL, true, "seconds",
977               "Causes the invoking thread to sleep for SECONDS seconds.\nSECONDS may be a value between 0 1and 1.")
978    {
979        @Override
980        public LispObject execute(LispObject arg)
981        {
982
983            try {
984                Thread.sleep(javaSleepInterval(arg));
985            }
986            catch (InterruptedException e) {
987                currentThread().processThreadInterrupts();
988            }
989            return NIL;
990        }
991    };
992
993    // ### mapcar-threads
994    private static final Primitive MAPCAR_THREADS =
995        new Primitive("mapcar-threads", PACKAGE_THREADS, true, "function",
996          "Applies FUNCTION to all existing threads.")
997    {
998        @Override
999        public LispObject execute(LispObject arg)
1000        {
1001            Function fun = checkFunction(arg);
1002            final LispThread thread = LispThread.currentThread();
1003            LispObject result = NIL;
1004            Iterator it = map.values().iterator();
1005            while (it.hasNext()) {
1006                LispObject[] args = new LispObject[1];
1007                args[0] = (LispThread) it.next();
1008                result = new Cons(funcall(fun, args, thread), result);
1009            }
1010            return result;
1011        }
1012    };
1013
1014    // ### destroy-thread
1015    private static final Primitive DESTROY_THREAD =
1016        new Primitive("destroy-thread", PACKAGE_THREADS, true, "thread", 
1017          "Mark THREAD as destroyed.")
1018    {
1019        @Override
1020        public LispObject execute(LispObject arg)
1021        {
1022            final LispThread thread;
1023            if (arg instanceof LispThread) {
1024                thread = (LispThread) arg;
1025            }
1026            else {
1027                return type_error(arg, Symbol.THREAD);
1028            }
1029            thread.setDestroyed(true);
1030            return T;
1031        }
1032    };
1033
1034    // ### interrupt-thread thread function &rest args => T
1035    // Interrupts thread and forces it to apply function to args. When the
1036    // function returns, the thread's original computation continues. If
1037    // multiple interrupts are queued for a thread, they are all run, but the
1038    // order is not guaranteed.
1039    private static final Primitive INTERRUPT_THREAD =
1040        new Primitive("interrupt-thread", PACKAGE_THREADS, true,
1041          "thread function &rest args",
1042          "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.")
1043    {
1044        @Override
1045        public LispObject execute(LispObject[] args)
1046        {
1047            if (args.length < 2)
1048                return error(new WrongNumberOfArgumentsException(this));
1049            final LispThread thread;
1050            if (args[0] instanceof LispThread) {
1051                thread = (LispThread) args[0];
1052            }
1053            else {
1054                return type_error(args[0], Symbol.THREAD);
1055            }
1056            LispObject fun = args[1];
1057            LispObject funArgs = NIL;
1058            for (int i = args.length; i-- > 2;)
1059                funArgs = new Cons(args[i], funArgs);
1060            thread.interrupt(fun, funArgs);
1061            return T;
1062        }
1063    };
1064
1065    // ### current-thread
1066    private static final Primitive CURRENT_THREAD =
1067        new Primitive("current-thread", PACKAGE_THREADS, true, "",
1068          "Returns a reference to invoking thread.")
1069    {
1070        @Override
1071        public LispObject execute()
1072        {
1073            return currentThread();
1074        }
1075    };
1076
1077    // ### backtrace
1078    private static final Primitive BACKTRACE =
1079        new Primitive("backtrace", PACKAGE_SYS, true, "",
1080          "Returns a backtrace of the invoking thread.")
1081    {
1082        @Override
1083        public LispObject execute(LispObject[] args)
1084
1085        {
1086            if (args.length > 1)
1087                return error(new WrongNumberOfArgumentsException(this));
1088            int limit = args.length > 0 ? Fixnum.getValue(args[0]) : 0;
1089            return currentThread().backtrace(limit);
1090        }
1091    };
1092    // ### frame-to-string
1093    private static final Primitive FRAME_TO_STRING =
1094        new Primitive("frame-to-string", PACKAGE_SYS, true, "frame")
1095    {
1096        @Override
1097        public LispObject execute(LispObject[] args)
1098
1099        {
1100            if (args.length != 1)
1101                return error(new WrongNumberOfArgumentsException(this));
1102           
1103            return checkStackFrame(args[0]).toLispString();
1104        }
1105    };
1106
1107    // ### frame-to-list
1108    private static final Primitive FRAME_TO_LIST =
1109        new Primitive("frame-to-list", PACKAGE_SYS, true, "frame")
1110    {
1111        @Override
1112        public LispObject execute(LispObject[] args)
1113
1114        {
1115            if (args.length != 1)
1116                return error(new WrongNumberOfArgumentsException(this));
1117
1118            return checkStackFrame(args[0]).toLispList();
1119        }
1120    };
1121
1122
1123    static {
1124        //FIXME: this block has been added for pre-0.16 compatibility
1125        // and can be removed the latest at release 0.22
1126        PACKAGE_EXT.export(intern("MAKE-THREAD", PACKAGE_THREADS));
1127        PACKAGE_EXT.export(intern("THREADP", PACKAGE_THREADS));
1128        PACKAGE_EXT.export(intern("THREAD-ALIVE-P", PACKAGE_THREADS));
1129        PACKAGE_EXT.export(intern("THREAD-NAME", PACKAGE_THREADS));
1130        PACKAGE_EXT.export(intern("MAPCAR-THREADS", PACKAGE_THREADS));
1131        PACKAGE_EXT.export(intern("DESTROY-THREAD", PACKAGE_THREADS));
1132        PACKAGE_EXT.export(intern("INTERRUPT-THREAD", PACKAGE_THREADS));
1133        PACKAGE_EXT.export(intern("CURRENT-THREAD", PACKAGE_THREADS));
1134    }
1135
1136    // ### use-fast-calls
1137    private static final Primitive USE_FAST_CALLS =
1138        new Primitive("use-fast-calls", PACKAGE_SYS, true)
1139    {
1140        @Override
1141        public LispObject execute(LispObject arg)
1142        {
1143            use_fast_calls = (arg != NIL);
1144            return use_fast_calls ? T : NIL;
1145        }
1146    };
1147
1148    // ### synchronized-on
1149    private static final SpecialOperator SYNCHRONIZED_ON =
1150        new SpecialOperator("synchronized-on", PACKAGE_THREADS, true,
1151                            "form &body body")
1152    {
1153        @Override
1154        public LispObject execute(LispObject args, Environment env)
1155
1156        {
1157          if (args == NIL)
1158            return error(new WrongNumberOfArgumentsException(this));
1159
1160          LispThread thread = LispThread.currentThread();
1161          synchronized (eval(args.car(), env, thread).lockableInstance()) {
1162              return progn(args.cdr(), env, thread);
1163          }
1164        }
1165    };
1166
1167    // ### object-wait
1168    private static final Primitive OBJECT_WAIT =
1169        new Primitive("object-wait", PACKAGE_THREADS, true,
1170                      "object &optional timeout")
1171    {
1172        @Override
1173        public LispObject execute(LispObject object)
1174
1175        {
1176            try {
1177                object.lockableInstance().wait();
1178            }
1179            catch (InterruptedException e) {
1180                currentThread().processThreadInterrupts();
1181            }
1182            catch (IllegalMonitorStateException e) {
1183                return error(new IllegalMonitorState());
1184            }
1185            return NIL;
1186        }
1187
1188        @Override
1189        public LispObject execute(LispObject object, LispObject timeout)
1190
1191        {
1192            try {
1193                object.lockableInstance().wait(javaSleepInterval(timeout));
1194            }
1195            catch (InterruptedException e) {
1196                currentThread().processThreadInterrupts();
1197            }
1198            catch (IllegalMonitorStateException e) {
1199                return error(new IllegalMonitorState());
1200            }
1201            return NIL;
1202        }
1203    };
1204
1205    // ### object-notify
1206    private static final Primitive OBJECT_NOTIFY =
1207        new Primitive("object-notify", PACKAGE_THREADS, true,
1208                      "object")
1209    {
1210        @Override
1211        public LispObject execute(LispObject object)
1212
1213        {
1214            try {
1215                object.lockableInstance().notify();
1216            }
1217            catch (IllegalMonitorStateException e) {
1218                return error(new IllegalMonitorState());
1219            }
1220            return NIL;
1221        }
1222    };
1223
1224    // ### object-notify-all
1225    private static final Primitive OBJECT_NOTIFY_ALL =
1226        new Primitive("object-notify-all", PACKAGE_THREADS, true,
1227                      "object")
1228    {
1229        @Override
1230        public LispObject execute(LispObject object)
1231
1232        {
1233            try {
1234                object.lockableInstance().notifyAll();
1235            }
1236            catch (IllegalMonitorStateException e) {
1237                return error(new IllegalMonitorState());
1238            }
1239            return NIL;
1240        }
1241    };
1242
1243
1244}
Note: See TracBrowser for help on using the repository browser.