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

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

Remove 'private' keyword to eliminate the Java requirement

for the compiler to generate synthetic accessors: functions that
don't appear in the source but do appear in the class file.

Patch by: Douglas Miles <dmiles _at_ users.sf.net>

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