source: trunk/abcl/src/org/armedbear/lisp/LispThread.java @ 12064

Last change on this file since 12064 was 12064, checked in by ehuelsmann, 16 years ago

Lisp stack efficiency: Use a stack of linked objects,
instead of Cons or LinkedList?.

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