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

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

Rename ConditionThrowable? to ControlTransfer? and remove

try/catch blocks which don't have anything to do with
non-local transfer of control.

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