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

Last change on this file was 11754, checked in by vvoutilainen, 16 years ago

Convert using ClassCastException? to checking instanceof.
Performance tests show this approach to be faster.
Patch by Douglas R. Miles. I modified the patch to
remove tabs, so indentation may be slightly off in places.
That's something that we need to handle separately, abcl
doesn't have a clear indentation policy.

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