Develop and Download Open Source Software

Browse CVS Repository

Contents of /netruby/netruby/Thread.cs

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (vendor branch)
Mon Apr 8 13:30:09 2002 UTC (22 years ago) by arton
Branch: MAIN, vendor
CVS Tags: start, HEAD
Changes since 1.1: +0 -0 lines
initial version 0.8

1 /*
2 Copyright(C) 2001-2002 arton
3
4 Permission is granted for use, copying, modification, distribution,
5 and distribution of modified versions of this work as long as the
6 above copyright notice is included.
7 */
8 using System;
9 using System.Diagnostics;
10 using System.Collections;
11 using System.IO;
12 using System.Text;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Threading;
16 using System.Security;
17
18 namespace arton.NETRuby
19 {
20 public class Scope : RBasic, ICloneable
21 {
22 public Scope(NetRuby r) :
23 base(r, null)
24 {
25 flag = 0;
26 local_tbl = null;
27 local_vars = null;
28 }
29 internal void InitLocal(uint[] tbl)
30 {
31 lock (this)
32 {
33 local_tbl = tbl;
34 if (local_vars != null)
35 {
36 object[] vars = new object[tbl.Length];
37 Array.Copy(local_vars, vars, local_vars.Length);
38 local_vars = vars;
39 }
40 else
41 {
42 local_vars = new object[tbl.Length];
43 }
44 }
45 }
46 public void InitLocal(uint[] tbl, object[] vars)
47 {
48 lock (this)
49 {
50 local_tbl = tbl;
51 local_vars = vars;
52 }
53 }
54 public object Clone()
55 {
56 lock (this)
57 {
58 Scope s = (Scope)MemberwiseClone();
59 s.Dup();
60 return s;
61 }
62 }
63 internal object this[int idx]
64 {
65 get {
66 if (local_vars == null) return null;
67 return local_vars[idx];
68 }
69 }
70
71 internal void Dup()
72 {
73 flag |= DONT_RECYCLE;
74 if (local_tbl != null)
75 {
76 local_vars = (object[])local_vars.Clone();
77 }
78 }
79 public override bool Equals(object o)
80 {
81 // Bypass RBasic's Equals
82 return (this == o);
83 }
84 public override int GetHashCode()
85 {
86 return base.GetHashCode();
87 }
88 public enum ScopeMode {
89 Public = 0,
90 Private = 1,
91 Protected = 2,
92 ModFunc = 5,
93 Mask = 7,
94 }
95
96 internal const int XHR = 1;
97 internal const int DONT_RECYCLE = 4;
98 internal bool DontRecycle
99 {
100 get { return (flag & DONT_RECYCLE) != 0; }
101 }
102 int flag;
103 internal uint[] local_tbl;
104 public object[] local_vars;
105 }
106
107 public class Block
108 {
109 internal Block(RThread th, RNode vr, RNode bd, object slf)
110 {
111 origThread = th;
112 tag = new BTag(th.ruby);
113 var = vr;
114 body = bd;
115 self = slf;
116 frame = (Frame)th.frame.Clone();
117 klass = th.rClass;
118 frame.file = th.file;
119 frame.line = th.line;
120 scope = th.scope;
121 prev = th.block;
122 iter = (ITER)th.iter.Peek();
123 vMode = th.ScopeMode;
124 flags = Flag.DScope;
125 dyna_vars = th.dyna_vars;
126 wrapper = th.wrapper;
127 }
128 internal bool CheckTag(Tag.TAG tg)
129 {
130 return (tg == tag.dst);
131 }
132 internal Tag.TAG DStatus
133 {
134 get { return tag.dst; }
135 set { tag.dst = value; }
136 }
137 internal int TagID
138 {
139 get { return tag.GetHashCode(); }
140 }
141 internal bool IsTag
142 {
143 get { return tag != null; }
144 }
145 internal bool IsDynamic
146 {
147 get { return (flags & Flag.Dynamic) != 0; }
148 set { if (value) flags |= Flag.Dynamic; else flags &= ~Flag.Dynamic; }
149 }
150 internal bool Orphan
151 {
152 set { if (value) flags |= Flag.Orphan; else flags &= ~Flag.Orphan; }
153 }
154 public bool DScope
155 {
156 get { return (flags & Flag.DScope) != 0; }
157 set { if (value) flags |= Flag.DScope; else flags &= ~Flag.DScope; }
158 }
159 internal class BTag : RBasic
160 {
161 internal BTag(NetRuby rb) :
162 base(rb, null)
163 {
164 tflags = 0;
165 dst = Tag.TAG.EMPTY;
166 GetHashCode();
167 }
168 internal Tag.TAG dst;
169 internal int tflags;
170 }
171 internal RNode var;
172 internal RNode body;
173 internal object self;
174 internal Frame frame;
175 public Scope scope;
176 BTag tag;
177 enum Flag
178 {
179 DScope = 1,
180 Dynamic = 2,
181 Orphan = 4,
182 }
183 Flag flags;
184 internal RMetaObject klass;
185 internal ITER iter;
186 internal Scope.ScopeMode vMode;
187 internal RVarmap dyna_vars;
188 internal RThread origThread;
189 internal RModule wrapper;
190 internal Block prev;
191
192 internal Block Clone()
193 {
194 Block c = (Block)MemberwiseClone();
195 // c.scope = (Scope)scope.Clone();
196 return c;
197 }
198 internal void DupPrev()
199 {
200 lock (this)
201 {
202 Block blk = this;
203 while (blk.prev != null)
204 {
205 Block tmp = (Block)blk.prev.Clone();
206 tmp.frame.DupArgs();
207 tmp.scope = (Scope)tmp.scope.Clone();
208 blk.prev = tmp;
209 blk = tmp;
210 }
211 }
212 }
213
214 internal bool IsOrphan(RThread th)
215 {
216 if (scope != null && th.scopes.Contains(scope) == false)
217 {
218 return true;
219 }
220 if (origThread != th)
221 {
222 return true;
223 }
224 return false;
225 }
226 }
227
228 public enum ITER
229 {
230 NOT = 0,
231 PRE = 1,
232 CUR = 2,
233 }
234
235 public class Frame : ICloneable
236 {
237 internal Frame()
238 {
239 prev = null;
240 tmp = null;
241 args = null;
242 line = 0;
243 iter = ITER.NOT;
244 byScopedCall = false;
245 }
246
247 internal Frame(RThread th)
248 {
249 prev = th.frame;
250 file = th.file;
251 line = th.line;
252 iter = (ITER)th.iter.Peek();
253 if (prev != null)
254 {
255 cBase = prev.cBase;
256 }
257 tmp = null;
258 args = null;
259 byScopedCall = false;
260 }
261 internal Frame(Frame curr)
262 {
263 self = curr.self;
264 args = curr.args;
265 byScopedCall = curr.byScopedCall;
266 lastFunc = curr.lastFunc;
267 cBase = curr.cBase;
268 prev = curr.prev;
269 tmp = curr;
270 file = curr.file;
271 line = curr.line;
272 iter = curr.iter;
273 }
274 public object Clone()
275 {
276 return MemberwiseClone();
277 }
278 public Frame Dup()
279 {
280 Frame nf = (Frame)MemberwiseClone();
281 Frame top = nf;
282 for (;;)
283 {
284 if (nf.args != null)
285 {
286 nf.args = (object[])nf.args.Clone();
287 }
288 nf.tmp = null;
289 if (nf.prev == null) break;
290 nf.prev = (Frame)nf.prev.Clone();
291 nf = nf.prev;
292 }
293 return top;
294 }
295 internal void CopyFromPrev()
296 {
297 self = prev.self;
298 lastFunc = prev.lastFunc;
299 lastClass = prev.lastClass;
300 args = prev.args;
301 }
302 internal object self;
303 private object[] args;
304 bool byScopedCall;
305 internal uint lastFunc;
306 internal RMetaObject lastClass;
307 void CheckLastClass(NetRuby ruby)
308 {
309 if (lastClass == null)
310 throw new eNameError(String.Format("superclass method `{0}' disabled",
311 ruby.id2name(lastFunc)));
312 }
313 public object[] LastArgs
314 {
315 get {
316 if (byScopedCall && args != null)
317 {
318 object[] argv = new object[args.Length - 2];
319 Array.Copy(args, 2, argv, 0, args.Length - 2);
320 return argv;
321 }
322 return args;
323 }
324 }
325 public object GetLastArg(int idx)
326 {
327 if (byScopedCall)
328 return args[idx + 2];
329 else
330 return args[idx];
331 }
332 internal void SetLastArgs(object[] tbl, bool inScopedCall)
333 {
334 byScopedCall = inScopedCall;
335 args = tbl;
336 }
337 internal int ArgCount
338 {
339 get { return (args == null) ? 0 : args.Length - 2; }
340 }
341 internal void DupArgs()
342 {
343 if (args != null)
344 {
345 args = (object[])args.Clone();
346 }
347 }
348 public object SuperCall(NetRuby ruby, RThread th, object[] args)
349 {
350 CheckLastClass(ruby);
351 th.PushCurrentIter();
352 object result = ruby.Call(lastClass.super, self, lastFunc, args, 3);
353 th.PopIter();
354 return result;
355 }
356 internal RNCRef cBase; // constants base node
357 internal Frame prev;
358 internal Frame tmp;
359 internal string file;
360 internal int line;
361 internal ITER iter;
362 }
363
364 public class RThread : RData, ICloneable
365 {
366 internal RThread(NetRuby rb) :
367 base(rb, rb.cThread)
368 {
369 result = null;
370 safeLevel = 0;
371 threadId = AppDomain.GetCurrentThreadId();
372 thread = Thread.CurrentThread;
373 vMode = Scope.ScopeMode.Private;
374
375 frame = new Frame();
376 rb.topFrame = frame;
377 scopes = new Stack();
378 scope = new Scope(rb);
379 dyna_vars = null;
380 iter = new Stack();
381 iter.Push(ITER.NOT);
382 protTag = new Stack();
383 protTag.Push(null);
384
385 block = null;
386 lvtbl = null;
387
388 rClass = null;
389 wrapper = null;
390 cRef = null;
391
392 file = "ruby";
393 line = 0;
394 inEval = 0;
395 tracing = false;
396 errInfo = null;
397 lastCallStat = CALLSTAT.PUBLIC;
398
399 locals = null;
400 gid = 0;
401 }
402 internal RThread(NetRuby rb, RThread th) :
403 base(rb, rb.cThread)
404 {
405 result = null;
406 safeLevel = th.safeLevel;
407 gid = th.gid;
408 abortOnException = rb.cThread.abortOnException;
409 threadId = AppDomain.GetCurrentThreadId();
410 thread = Thread.CurrentThread;
411 vMode = Scope.ScopeMode.Private;
412
413 frame = (Frame)rb.topFrame.Dup();
414 frame.self = rb.topSelf;
415 frame.cBase = rb.topCRef;
416 scopes = new Stack();
417 scope = new Scope(rb);
418 dyna_vars = null;
419 iter = new Stack();
420 iter.Push(ITER.NOT);
421 protTag = new Stack();
422 protTag.Push(null);
423
424 block = null;
425 lvtbl = null;
426
427 rClass = rb.cObject;
428 wrapper = null;
429 cRef = rb.topCRef;
430
431 file = "ruby";
432 line = 0;
433 inEval = 0;
434 tracing = false;
435 errInfo = null;
436 lastCallStat = CALLSTAT.PUBLIC;
437
438 locals = null;
439 }
440
441 public object Clone()
442 {
443 RThread tx = null;
444 lock (this)
445 {
446 tx = (RThread)MemberwiseClone();
447 tx.errInfo = null;
448 tx.lastCallStat = CALLSTAT.PUBLIC;
449 tx.locals = null;
450 tx.iter = (Stack)iter.Clone();
451
452 tx.scopes = (Stack)scopes.Clone();
453 tx.frame = frame.Dup();
454 if (block != null)
455 {
456 tx.block.DupPrev();
457 }
458 }
459 tx.protTag = new Stack();
460 tx.protTag.Push(null);
461 tx.inEval = 0;
462 tx.threadId = 0;
463 return tx;
464 }
465
466 public bool AbortOnException
467 {
468 get { return abortOnException; }
469 set { abortOnException = value; }
470 }
471
472 public int Priority
473 {
474 get { return (int)thread.Priority; }
475 set { thread.Priority = (ThreadPriority)value; }
476 }
477
478 public bool HasError
479 {
480 get {
481 return (errInfo != null) ? true : false;
482 }
483 }
484 static System.Threading.ThreadState[] stopTbl = new System.Threading.ThreadState[] {
485 System.Threading.ThreadState.WaitSleepJoin,
486 System.Threading.ThreadState.Stopped,
487 System.Threading.ThreadState.Suspended,
488 System.Threading.ThreadState.Unstarted,
489 };
490 public bool IsStop
491 {
492 get {
493 if (thread.IsAlive == false) return true;
494 return (Array.IndexOf(stopTbl, thread.ThreadState) < 0) ? false : true;
495 }
496 }
497 public bool IsAlive
498 {
499 get { return thread.IsAlive; }
500 }
501 internal string ConvStat()
502 {
503 if (thread.IsAlive == false) return "dead";
504 System.Threading.ThreadState st = thread.ThreadState;
505 if ((st & System.Threading.ThreadState.AbortRequested) != 0)
506 return "aborting";
507 if ((st & (System.Threading.ThreadState.WaitSleepJoin
508 | System.Threading.ThreadState.Stopped
509 | System.Threading.ThreadState.Suspended)) != 0)
510 return "sleep";
511 if (st == System.Threading.ThreadState.Running ||
512 (st & (System.Threading.ThreadState.Background
513 | System.Threading.ThreadState.SuspendRequested
514 | System.Threading.ThreadState.StopRequested
515 | System.Threading.ThreadState.Unstarted)) != 0)
516 return "run";
517
518 return String.Format("unknown({0})", st.ToString());
519 }
520 public override object Inspect()
521 {
522 string cname = ruby.ClassOf(this).Name;
523 string str = String.Format("#<{0}:0x{1:x8} {2}>", cname,
524 threadId, ConvStat());
525 if (IsTainted)
526 {
527 return new RString(ruby, str, true);
528 }
529 return str;
530 }
531
532 internal RMetaObject cBase
533 {
534 get { return frame.cBase.clss; }
535 }
536 internal Frame DupFrame()
537 {
538 return frame = new Frame(frame);
539 }
540 internal void CopyPrevFrame()
541 {
542 lock (this)
543 {
544 frame.CopyFromPrev();
545 }
546 }
547 internal Frame PushFrame(bool makedummy)
548 {
549 lock (this)
550 {
551 frame = new Frame(this);
552 if (makedummy)
553 {
554 if (frame.prev.prev != null)
555 frame = (Frame)frame.prev.prev.Clone();
556 }
557 }
558 return frame;
559 }
560 internal void PopFrame()
561 {
562 lock (this)
563 {
564 file = frame.file;
565 line = frame.line;
566 frame = frame.prev;
567 }
568 }
569 public void SaveArgs(bool newScope)
570 {
571 frame.SetLastArgs(scope.local_vars, newScope);
572 }
573 internal void PushTag(Tag.TAG t)
574 {
575 protTag.Push(new Tag(t, this));
576 }
577 internal Tag PopTag(bool setResult)
578 {
579 Tag tag = (Tag)protTag.Pop();
580 if (setResult)
581 {
582 tag.SetResult((Tag)protTag.Peek());
583 }
584 return tag;
585 }
586 internal Tag CurrentTag
587 {
588 get { return (Tag)protTag.Peek(); }
589 }
590 internal void TagJump(Tag.TAG state)
591 {
592 Tag tag = (Tag)protTag.Peek();
593 if (tag != null)
594 {
595 tag.Jump(state, this);
596 }
597 }
598 public void PushIter(ITER i)
599 {
600 iter.Push(i);
601 }
602 public void PushCurrentIter()
603 {
604 iter.Push(((ITER)iter.Peek() != ITER.NOT) ? ITER.PRE : ITER.NOT);
605 }
606 public void PopIter()
607 {
608 iter.Pop();
609 }
610 internal bool IsBlockGiven
611 {
612 get { return (frame.iter != 0); }
613 }
614
615 internal bool IsPriorBlockGiven
616 {
617 get {
618 if (frame.prev != null && frame.prev.iter != 0 && block != null)
619 return true;
620 return false;
621 }
622 }
623 internal void CompileError(string s)
624 {
625 ErrorAppend(s);
626 nerrs++;
627 }
628 internal void ErrorAppend(string s)
629 {
630 if (inEval > 0)
631 {
632 if (errInfo != null)
633 {
634 StringBuilder sb = new StringBuilder(errInfo.ToString());
635 sb.AppendFormat("\n{0}", s);
636 s = sb.ToString();
637 }
638 errInfo = new RException(ruby, s, ruby.eSyntaxError);
639 }
640 else
641 {
642 System.Console.Error.WriteLine(s);
643 }
644 }
645 internal int errorHandle(Exception exc)
646 {
647 Tag.TAG state = (exc is eTagJump) ? ((eTagJump)exc).state : Tag.TAG.RAISE;
648 int ex = 0;
649 switch (state & Tag.TAG.MASK) {
650 case Tag.TAG.EMPTY:
651 ex = 0;
652 break;
653 case Tag.TAG.RETURN:
654 errorPos();
655 System.Console.Error.WriteLine(": unexpected return");
656 ex = 1;
657 break;
658 case Tag.TAG.NEXT:
659 errorPos();
660 System.Console.Error.WriteLine(": unexpected next");
661 ex = 1;
662 break;
663 case Tag.TAG.BREAK:
664 errorPos();
665 System.Console.Error.WriteLine(": unexpected break");
666 ex = 1;
667 break;
668 case Tag.TAG.REDO:
669 errorPos();
670 System.Console.Error.WriteLine(": unexpected redo");
671 ex = 1;
672 break;
673 case Tag.TAG.RETRY:
674 errorPos();
675 System.Console.Error.WriteLine(": retry outside of rescue clause");
676 ex = 1;
677 break;
678 case Tag.TAG.RAISE:
679 case Tag.TAG.FATAL:
680 ruby.errorPrint(this, exc);
681 ex = 1;
682 break;
683 default:
684 ruby.bug("Unknown longjmp status " + ex.ToString());
685 break;
686 }
687 return ex;
688 }
689 internal void errorPos()
690 {
691 string s;
692 if (file != null)
693 {
694 if (frame.lastFunc != 0)
695 {
696 s = String.Format("{0}:{1}:in `{2}'",
697 file, line, ruby.id2name(frame.lastFunc));
698 }
699 else if (line == 0)
700 {
701 s = file;
702 }
703 else
704 {
705 s = String.Format("{0}:{1}", file, line);
706 }
707 System.Console.Error.Write(s);
708 }
709 }
710
711 Scope.ScopeMode vMode;
712 public RMetaObject PushClass(RMetaObject klass)
713 {
714 RMetaObject old = rClass;
715 rClass = klass;
716 return old;
717 }
718 public void PopClass(RMetaObject org)
719 {
720 rClass = org;
721 }
722 //
723 public Scope.ScopeMode PushScope()
724 {
725 Scope.ScopeMode vm = vMode;
726 Scope sc = new Scope(ruby);
727 scopes.Push(scope);
728 scope = sc;
729 vMode = Scope.ScopeMode.Public;
730 return vm;
731 }
732 public void PopScope(Scope.ScopeMode vm)
733 {
734 scope = (Scope)scopes.Pop();
735 vMode = vm;
736 }
737 internal Scope.ScopeMode ScopeMode
738 {
739 get { return vMode; }
740 }
741 internal void ScopeSet(Scope.ScopeMode f)
742 {
743 vMode = f;
744 }
745 internal bool ScopeTest(Scope.ScopeMode f)
746 {
747 return (vMode & f) != 0;
748 }
749 internal ITER Iter
750 {
751 get { return (ITER)iter.Peek();}
752 }
753 public Block IterBlock(RNode var, RNode body, object self)
754 {
755 PushTag(Tag.TAG.PROT_FUNC);
756 block = new Block(this, var, body, self);
757 return block;
758 }
759 public void ResetIterBlock(Block _block)
760 {
761 PopTag(false);
762 if (_block.IsDynamic)
763 {
764 _block.Orphan = true;
765 }
766 block = _block.prev;
767 }
768 public Block AdjustBlock()
769 {
770 Block blk = block;
771 if ((ITER)iter.Peek() == ITER.PRE)
772 {
773 block = block.prev;
774 }
775 iter.Push(ITER.NOT);
776 return blk;
777 }
778 public void RestoreBlock(Block blk)
779 {
780 block = blk;
781 iter.Pop();
782 }
783 // Locals
784 internal RVarmap DynaPush()
785 {
786 RVarmap vars = dyna_vars;
787
788 dvar_push(0, null);
789 lvtbl.dlev++;
790 return vars;
791 }
792
793 internal void DynaPop(RVarmap vars)
794 {
795 lvtbl.dlev--;
796 dyna_vars = vars;
797 }
798 public void InitLVar(uint[] tbl, object[] vars)
799 {
800 scope.InitLocal(tbl, vars);
801 }
802 public object LoadLVar(int ct)
803 {
804 if (scope.local_vars == null)
805 {
806 ruby.bug("unexpected local variable");
807 }
808 return scope.local_vars[ct];
809 }
810 public void SetLVar(int ct, object val)
811 {
812 if (scope.local_vars == null)
813 {
814 ruby.bug("unexpected local variable assignment");
815 }
816 scope.local_vars[ct] = val;
817 }
818
819 internal RVarmap new_dvar(uint id, object value, RVarmap prev)
820 {
821 RVarmap vars = new RVarmap(ruby, id, value, prev);
822 return vars;
823 }
824
825 internal bool dvar_defined(uint id)
826 {
827 RVarmap vars = dyna_vars;
828 while (vars != null)
829 {
830 if (vars.id == id) return true;
831 vars = vars.next;
832 }
833 return false;
834 }
835
836 internal bool dvar_curr(uint id)
837 {
838 RVarmap vars = dyna_vars;
839 while (vars != null)
840 {
841 if (vars.id == 0) break;
842 if (vars.id == id) return true;
843 vars = vars.next;
844 }
845 return false;
846 }
847
848 internal void dvar_push(uint id, object value)
849 {
850 lock (this)
851 {
852 dyna_vars = new_dvar(id, value, dyna_vars);
853 }
854 }
855 private void DVarAsgn(uint id, object val, bool curr)
856 {
857 RVarmap vars = dyna_vars;
858 while (vars != null)
859 {
860 if (curr && vars.id == id)
861 {
862 vars.val = val;
863 return;
864 }
865 vars = vars.next;
866 }
867 if (dyna_vars == null)
868 {
869 dyna_vars = new_dvar(id, val, null);
870 }
871 else
872 {
873 vars = new_dvar(id, val, dyna_vars.next);
874 dyna_vars.next = vars;
875 }
876 }
877 public void DVarAsgn(uint id, object val)
878 {
879 DVarAsgn(id, val, false);
880 }
881 public void DVarAsgnCurr(uint id, object val)
882 {
883 DVarAsgn(id, val, true);
884 }
885 public object DVarRef(uint id)
886 {
887 RVarmap vars = dyna_vars;
888 while (vars != null)
889 {
890 if (vars.id == id)
891 {
892 return vars.val;
893 }
894 vars = vars.next;
895 }
896 return null;
897 }
898
899 internal bool IsDynaInBlock
900 {
901 get { return (lvtbl.dlev > 0); }
902 }
903
904 internal bool LocalID(uint id)
905 {
906 if (lvtbl == null || lvtbl.tbl == null) return false;
907 return (Array.IndexOf(lvtbl.tbl, id, 2) < 0) ? false : true;
908 }
909
910 void SpecialLocalSet(char c, object val)
911 {
912 TopLocalInit();
913 int cnt = LocalCnt((uint)c);
914 TopLocalSetup();
915 scope.local_vars[cnt] = val;
916 }
917
918 internal void TopLocalInit()
919 {
920 LocalPush();
921 int cnt = (scope.local_tbl != null) ? scope.local_tbl.Length : 0;
922 lvtbl.Init(cnt, scope.local_tbl, (dyna_vars != null));
923 }
924
925 internal void TopLocalSetup()
926 {
927 int len = lvtbl.Length;
928
929 if (len > 0)
930 {
931 scope.InitLocal(lvtbl.tbl);
932 }
933 LocalPop();
934 }
935
936 internal void LocalPush()
937 {
938 LocalVars local = new LocalVars(lvtbl, 0, 0);
939 lvtbl = local;
940 }
941 internal void LocalPop()
942 {
943 LocalVars local = lvtbl.prev;
944 if (lvtbl.tbl != null)
945 {
946 lvtbl.tbl = null;
947 }
948 lvtbl = local;
949 }
950 internal int LocalAppend(uint id)
951 {
952 return lvtbl.Append(id);
953 }
954
955 internal int LocalCnt(uint id)
956 {
957 return lvtbl.Count(id);
958 }
959 internal uint[] Locals
960 {
961 get { return lvtbl.tbl; }
962 }
963
964 internal object BackRef
965 {
966 get { return scope[1]; }
967 set {
968 if (scope.local_vars == null)
969 SpecialLocalSet('~', value);
970 else
971 scope.local_vars[1] = value;
972 }
973 }
974
975 internal Thread Owner
976 {
977 get { return thread; }
978 set { thread = value; }
979 }
980
981 public void EnterEval()
982 {
983 inEval++;
984 }
985 public void LeaveEval()
986 {
987 inEval--;
988 }
989 internal bool IsInEval
990 {
991 get { return (inEval > 0); }
992 }
993 internal void ClearCompileError()
994 {
995 nerrs = 0;
996 }
997 internal bool CompileFailed
998 {
999 get { return (nerrs > 0); }
1000 }
1001
1002 internal object result;
1003
1004 internal RNode evalTreeBegin = null;
1005 internal RNode evalTree = null;
1006 //
1007 internal Frame frame;
1008 public Frame CurrentFrame
1009 {
1010 get { return frame; }
1011 }
1012 public Scope scope;
1013 internal RVarmap dyna_vars;
1014 internal Block block;
1015 internal Stack scopes;
1016 internal Stack iter;
1017 internal Stack protTag;
1018 internal RMetaObject rClass;
1019 public RMetaObject OuterClass
1020 {
1021 get {
1022 if (rClass == null)
1023 throw new eTypeError("no outer class/module");
1024 return rClass;
1025 }
1026 }
1027 internal RModule wrapper;
1028 internal RNCRef cRef;
1029 private LocalVars lvtbl;
1030 internal Thread thread;
1031 internal int gid;
1032 public string file;
1033 public int line;
1034 internal bool tracing;
1035 public RException errInfo;
1036 private int inEval;
1037 private int nerrs;
1038 internal CALLSTAT lastCallStat;
1039 private object[] args;
1040
1041 internal int safeLevel;
1042 int threadId;
1043 bool abortOnException;
1044
1045 internal st_table locals;
1046
1047 public void SetWrapper(RBasic klass)
1048 {
1049 if (wrapper != null)
1050 {
1051 RMetaObject.ExtendObject(klass, wrapper);
1052 RMetaObject.IncludeModule((RMetaObject)klass, wrapper);
1053 }
1054 }
1055 internal void Secure(int level)
1056 {
1057 if (level <= safeLevel)
1058 {
1059 string s = String.Format("Insecure operation `{0}' at level {1}",
1060 ruby.id2name(frame.lastFunc), safeLevel);
1061 throw new SecurityException(s);
1062 }
1063 }
1064 internal void entry()
1065 {
1066 threadId = AppDomain.GetCurrentThreadId();
1067 PushTag(Tag.TAG.PROT_THREAD);
1068 try
1069 {
1070 result = ruby.Yield(args, null, null, true);
1071 }
1072 catch (eTagJump e)
1073 {
1074 if (e.state == Tag.TAG.RAISE && errInfo != null)
1075 {
1076 checkError();
1077 }
1078 }
1079 catch (Exception e)
1080 {
1081 errInfo = new RException(ruby, e);
1082 checkError();
1083 }
1084 PopTag(true);
1085 ruby.ClearContext(this);
1086 }
1087 void checkError()
1088 {
1089 if (safeLevel < 4 &&
1090 (abortOnException || ruby.cThread.AbortOnException || ruby.debug))
1091 {
1092 ruby.errorPrint(this);
1093 Environment.Exit(1);
1094 }
1095 }
1096 internal void run()
1097 {
1098 if (thread.IsAlive == false)
1099 throw new eThreadError("killed thread");
1100 if ((thread.ThreadState & System.Threading.ThreadState.WaitSleepJoin) != 0)
1101 thread.Interrupt();
1102 else if ((thread.ThreadState & System.Threading.ThreadState.Suspended) != 0)
1103 thread.Resume();
1104 }
1105 internal RThread exit()
1106 {
1107 if (Thread.CurrentThread != thread)
1108 {
1109 Secure(4);
1110 if (thread.IsAlive == false) return this;
1111 }
1112
1113 if (this == ruby.threadMain/* && ruby.threads.Count == 0 */)
1114 {
1115 ruby.Exit(0);
1116 }
1117 ruby.ClearContext(this);
1118 thread.Abort();
1119 return this;
1120 }
1121
1122 internal object join()
1123 {
1124 if (thread.IsAlive)
1125 {
1126 if (Thread.CurrentThread == thread)
1127 throw new eThreadError("thread tried to join itself");
1128 thread.Join();
1129 }
1130 if (errInfo != null)
1131 {
1132 throw new eTagJump(errInfo);
1133 }
1134 return result;
1135 }
1136
1137 internal object GetTLS(object key)
1138 {
1139 uint id = ruby.ToID(key);
1140 return LocalARef(id);
1141 }
1142
1143 internal object SetTLS(object key, object val)
1144 {
1145 RThread th = ruby.GetCurrentContext();
1146 if (th.safeLevel >= 4 && th != this)
1147 {
1148 throw new SecurityException("Insecure: can't modify thread locals");
1149 }
1150 if (IsFrozen) ruby.ErrorFrozen("thread locals");
1151 uint id = ruby.ToID(key);
1152 return LocalASet(id, val);
1153 }
1154 internal bool IsKey(object key)
1155 {
1156 if (locals == null) return false;
1157 return locals.ContainsKey(ruby.ToID(key));
1158 }
1159 internal object LocalARef(uint key)
1160 {
1161 if (locals == null) return null;
1162 object o;
1163 if (locals.lookup(key, out o)) return o;
1164 return null;
1165 }
1166 internal object LocalASet(uint key, object val)
1167 {
1168 lock (this)
1169 {
1170 if (locals == null)
1171 {
1172 locals = new st_table();
1173 }
1174 if (val == null)
1175 {
1176 locals.Remove(id);
1177 }
1178 else
1179 {
1180 locals[id] = val;
1181 }
1182 }
1183 return val;
1184 }
1185 public RThread Raise(object[] argv)
1186 {
1187 if (thread.IsAlive == false) return null;
1188 if (thread == Thread.CurrentThread)
1189 {
1190 ruby.ruby_raise(this, argv);
1191 }
1192 throw new NotSupportedException("NETRuby can't handle Thread#raise");
1193 }
1194
1195 static internal RThread Start(NetRuby ruby, object[] args)
1196 {
1197 RThread parent = ruby.GetCurrentContext();
1198 RThread thrd = (RThread)parent.Clone();
1199 return thrd.Start(args);
1200 }
1201
1202 internal RThread Start(object[] argv)
1203 {
1204 thread = new Thread(new ThreadStart(entry));
1205 args = argv;
1206 ruby.AddContext(this);
1207 thread.Start();
1208 return this;
1209 }
1210
1211 internal void Init(NetRuby rb)
1212 {
1213 if (klass == null)
1214 klass = rb.cThread;
1215 rClass = rb.cObject;
1216 frame.self = rb.topSelf;
1217 cRef = rb.topCRef;
1218 abortOnException = rb.cThread.abortOnException;
1219
1220 RThreadGroup tg = (RThreadGroup)rb.cThreadGroup.ConstGetAt(rb.intern("Default"));
1221 tg.Add(this);
1222 }
1223 }
1224
1225 public class RThreadClass : RClass
1226 {
1227 private RThreadClass(NetRuby rb) :
1228 base(rb, "Thread", rb.cObject)
1229 {
1230 abortOnException = false;
1231 }
1232 internal bool abortOnException;
1233 public bool AbortOnException
1234 {
1235 get { return abortOnException; }
1236 set { abortOnException = value; }
1237 }
1238
1239 static public RBasic NewThread(object[] argv, RMetaObject meta)
1240 {
1241 NetRuby ruby = meta.ruby;
1242 RThread parent = ruby.GetCurrentContext();
1243 RThread thrd = (RThread)parent.Clone();
1244 thrd.thread = null;
1245 thrd.klass = meta;
1246 ruby.CallInit(thrd, argv);
1247 return thrd;
1248 }
1249
1250 static private RThread check(NetRuby rb, object o)
1251 {
1252 if (o is RThread == false)
1253 throw new eTypeError(String.Format("wrong argument type {0} (expected Thread)",
1254 rb.ClassOf(o).Name));
1255 return (RThread)o;
1256 }
1257 static internal object thread_new(RBasic r, params object[] args)
1258 {
1259 RBasic o = NewThread(args, (RMetaObject)r);
1260 return o;
1261 }
1262 static internal object initialize(RBasic r, params object[] args)
1263 {
1264 if (r.ruby.IsBlockGiven == false)
1265 {
1266 throw new eThreadError("must be called with a block");
1267 }
1268 return check(r.ruby, r).Start(args);
1269 }
1270 static internal object thread_start(RBasic r, params object[] args)
1271 {
1272 if (r.ruby.IsBlockGiven == false)
1273 {
1274 throw new eThreadError("must be called with a block");
1275 }
1276 return RThread.Start(r.ruby, args);
1277 }
1278 static internal object thread_stop(RBasic r, params object[] args)
1279 {
1280 RThread th = r.ruby.GetCurrentContext();
1281 if (th.thread != null && th.thread.IsAlive)
1282 {
1283 th.thread.Suspend();
1284 }
1285 return null;
1286 }
1287 static internal object thread_s_kill(RBasic r, params object[] args)
1288 {
1289 return check(r.ruby, args[0]).exit();
1290 }
1291 static internal object thread_exit(RBasic r, params object[] args)
1292 {
1293 RThread th = r.ruby.GetCurrentContext();
1294 return th.exit();
1295 }
1296 static internal object thread_pass(RBasic r, params object[] args)
1297 {
1298 Thread.Sleep(0);
1299 return null;
1300 }
1301 static internal object thread_current(RBasic r, params object[] args)
1302 {
1303 return r.ruby.GetCurrentContext();
1304 }
1305 static internal object thread_main(RBasic r, params object[] args)
1306 {
1307 return r.ruby.threadMain;
1308 }
1309 static internal object thread_list(RBasic r, params object[] args)
1310 {
1311 return r.ruby.ThreadList;
1312 }
1313
1314 static internal object thread_run(RBasic r, params object[] args)
1315 {
1316 ((RThread)r).run();
1317 return r;
1318 }
1319 static internal object thread_wakeup(RBasic r, params object[] args)
1320 {
1321 return thread_run(r, args);
1322 }
1323 static internal object thread_kill(RBasic r, params object[] args)
1324 {
1325 return ((RThread)r).exit();
1326 }
1327 static internal object thread_value(RBasic r, params object[] args)
1328 {
1329 return ((RThread)r).join();
1330 }
1331 static internal object thread_status(RBasic r, params object[] args)
1332 {
1333 RThread th = (RThread)r;
1334 Thread thrd = th.thread;
1335 string s = th.ConvStat();
1336 if (th.IsAlive == false)
1337 {
1338 if (th.HasError) return null;
1339 return false;
1340 }
1341 return s;
1342 }
1343 static internal object thread_join(RBasic r, params object[] args)
1344 {
1345 ((RThread)r).join();
1346 return r;
1347 }
1348 static internal object thread_alive(RBasic r, params object[] args)
1349 {
1350 RThread th = (RThread)r;
1351 return th.thread.IsAlive;
1352 }
1353 static internal object thread_isstop(RBasic r, params object[] args)
1354 {
1355 return ((RThread)r).IsStop;
1356 }
1357 static internal object thread_raise(RBasic r, params object[] args)
1358 {
1359 return ((RThread)r).Raise(args);
1360 }
1361 static internal object critical_getset(RBasic r, params object[] args)
1362 {
1363 throw new NotSupportedException("NETRuby can't handle Thread#critical");
1364 }
1365
1366 static internal object thread_s_abort_exc(RBasic r, params object[] args)
1367 {
1368 NetRuby rb = r.ruby;
1369 return rb.cThread.AbortOnException;
1370 }
1371 static internal object thread_s_abort_set(RBasic r, params object[] args)
1372 {
1373 NetRuby rb = r.ruby;
1374 bool b = RBasic.RTest(args[0]);
1375 rb.cThread.AbortOnException = b;
1376 return b;
1377 }
1378 static internal object thread_abort_exc(RBasic r, params object[] args)
1379 {
1380 return ((RThread)r).AbortOnException;
1381 }
1382 static internal object thread_abort_set(RBasic r, params object[] args)
1383 {
1384 bool b = RBasic.RTest(args[0]);
1385 ((RThread)r).AbortOnException = b;
1386 return b;
1387 }
1388
1389 static internal object thread_priority(RBasic r, params object[] args)
1390 {
1391 return ((RThread)r).Priority;
1392 }
1393 static int[] threadPtyVal = new int[] {
1394 (int)ThreadPriority.AboveNormal,
1395 (int)ThreadPriority.BelowNormal,
1396 (int)ThreadPriority.Highest,
1397 (int)ThreadPriority.Lowest,
1398 (int)ThreadPriority.Normal,
1399 };
1400 static internal object thread_priority_set(RBasic r, params object[] args)
1401 {
1402 NetRuby rb = r.ruby;
1403 long l = rb.InstanceOf(args[0]).ToInteger().ToLong();
1404 if (Array.IndexOf(threadPtyVal, (int)l) < 0)
1405 {
1406 throw new ArgumentException("invalid thread priority value");
1407 }
1408 ((RThread)r).Priority = (int)l;
1409 return null;
1410 }
1411 static internal object thread_safe_level(RBasic r, params object[] args)
1412 {
1413 return ((RThread)r).safeLevel;
1414 }
1415 static internal object thread_aref(RBasic r, params object[] args)
1416 {
1417 return ((RThread)r).GetTLS(args[0]);
1418 }
1419 static internal object thread_aset(RBasic r, params object[] args)
1420 {
1421 return ((RThread)r).SetTLS(args[0], args[1]);
1422 }
1423 static internal object thread_keyp(RBasic r, params object[] args)
1424 {
1425 return ((RThread)r).IsKey(args[0]);
1426 }
1427
1428 internal static void Init(NetRuby rb)
1429 {
1430 rb.eThreadError = rb.DefineClass("ThreadError", rb.eException);
1431
1432 RThreadClass t = new RThreadClass(rb);
1433 t.DefineClass("Thread", rb.cObject);
1434 rb.cThread = t;
1435 t.DefineSingletonMethod("new", new RMethod(thread_new), -1);
1436 t.DefineMethod("initialize", new RMethod(initialize), -2);
1437 t.DefineSingletonMethod("start", new RMethod(thread_start), -2);
1438 t.DefineSingletonMethod("fork", new RMethod(thread_start), -2);
1439 t.DefineSingletonMethod("stop", new RMethod(thread_stop), 0);
1440 t.DefineSingletonMethod("kill", new RMethod(thread_s_kill), 1);
1441 t.DefineSingletonMethod("exit", new RMethod(thread_exit), 0);
1442 t.DefineSingletonMethod("pass", new RMethod(thread_pass), 0);
1443 t.DefineSingletonMethod("current", new RMethod(thread_current), 0);
1444 t.DefineSingletonMethod("main", new RMethod(thread_main), 0);
1445 t.DefineSingletonMethod("list", new RMethod(thread_list), 0);
1446
1447 t.DefineSingletonMethod("critical", new RMethod(critical_getset), 0);
1448 t.DefineSingletonMethod("critical", new RMethod(critical_getset), 1);
1449 t.DefineSingletonMethod("abort_on_exception", new RMethod(thread_s_abort_exc), 0);
1450 t.DefineSingletonMethod("abort_on_exception=", new RMethod(thread_s_abort_set), 1);
1451
1452 t.DefineMethod("run", new RMethod(thread_run), 0);
1453 t.DefineMethod("wakeup", new RMethod(thread_wakeup), 0);
1454 t.DefineMethod("kill", new RMethod(thread_kill), 0);
1455 t.DefineMethod("exit", new RMethod(thread_kill), 0);
1456 t.DefineMethod("value", new RMethod(thread_value), 0);
1457 t.DefineMethod("status", new RMethod(thread_status), 0);
1458 t.DefineMethod("join", new RMethod(thread_join), 0);
1459 t.DefineMethod("alive?", new RMethod(thread_alive), 0);
1460 t.DefineMethod("stop?", new RMethod(thread_isstop), 0);
1461 t.DefineMethod("raise", new RMethod(thread_raise), 0);
1462
1463 t.DefineMethod("abort_on_exception", new RMethod(thread_abort_exc), 0);
1464 t.DefineMethod("abort_on_exception=", new RMethod(thread_abort_set), 1);
1465
1466 t.DefineMethod("priority", new RMethod(thread_priority), 0);
1467 t.DefineMethod("priority=", new RMethod(thread_priority_set), 1);
1468 t.DefineMethod("safe_level", new RMethod(thread_safe_level), 0);
1469
1470 t.DefineMethod("[]", new RMethod(thread_aref), 1);
1471 t.DefineMethod("[]=", new RMethod(thread_aset), 2);
1472 t.DefineMethod("key?", new RMethod(thread_keyp), 1);
1473 }
1474 }
1475
1476 public class RThreadGroup : RData
1477 {
1478 internal RThreadGroup(NetRuby rb, RMetaObject meta) :
1479 base(rb, meta)
1480 {
1481 gid = GetHashCode();
1482 }
1483 int gid;
1484 public RArray List
1485 {
1486 get {
1487 RArray array = new RArray(ruby, true);
1488 Hashtable threads = ruby.threads;
1489 lock (threads.SyncRoot)
1490 {
1491 foreach (DictionaryEntry ent in threads)
1492 {
1493 RThread r = (RThread)ent.Value;
1494 if (r.gid == gid) array.Add(r);
1495 }
1496 }
1497 if (ruby.threadMain.gid == gid)
1498 array.Add(ruby.threadMain);
1499 return array;
1500 }
1501 }
1502 public RThreadGroup Add(object o)
1503 {
1504 RThread th = ruby.GetCurrentContext();
1505 th.Secure(4);
1506 if (o is RThread == false)
1507 {
1508 throw new eTypeError(String.Format("wrong argument type {0} (expected Thread)",
1509 ruby.ClassOf(o).Name));
1510 }
1511 lock (o)
1512 {
1513 ((RThread)o).gid = gid;
1514 }
1515 return this;
1516 }
1517 }
1518
1519 public class RThreadGroupClass : RClass
1520 {
1521 private RThreadGroupClass(NetRuby rb) :
1522 base(rb, "ThreadGroup", rb.cObject)
1523 {
1524 }
1525 static public RBasic NewThreadGroup(object[] argv, RMetaObject meta)
1526 {
1527 NetRuby ruby = meta.ruby;
1528 RThreadGroup tg = new RThreadGroup(ruby, meta);
1529 ruby.CallInit(tg, argv);
1530 return tg;
1531 }
1532 static internal object tg_new(RBasic r, params object[] args)
1533 {
1534 return NewThreadGroup(args, (RMetaObject)r);
1535 }
1536 static internal object list(RBasic r, params object[] args)
1537 {
1538 return ((RThreadGroup)r).List;
1539 }
1540 static internal object add(RBasic r, params object[] args)
1541 {
1542 return ((RThreadGroup)r).Add(args[0]);
1543 }
1544
1545 internal static void Init(NetRuby rb)
1546 {
1547 RThreadGroupClass t = new RThreadGroupClass(rb);
1548 t.DefineClass("ThreadGroup", rb.cObject);
1549 rb.cThreadGroup = t;
1550 t.DefineSingletonMethod("new", new RMethod(tg_new), -1);
1551 t.DefineMethod("list", new RMethod(list), 0);
1552 t.DefineMethod("add", new RMethod(add), 1);
1553 RThreadGroup rg = (RThreadGroup)tg_new(t);
1554 t.ConstSet(rb.intern("Default"), rg);
1555 rg.Add(rb.GetCurrentContext());
1556 }
1557 }
1558 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26