1 using NUnit.Framework;
2 
3 using System;
4 using Mono.Tasklets;
5 
6 namespace MonoTests.System
7 {
8     [TestFixture]
9     public class ContinuationsTest
10     {
11         [TestFixtureSetUp]
FixtureSetUp()12         public void FixtureSetUp ()
13         {
14             try {
15                 var temp = new Continuation ();
16             } catch (NotImplementedException) {
17                 Assert.Ignore ("This platform doesn't support Tasklets.");
18             }
19         }
20 
21         int total = 0;
22 
23         [Test]
TestContinuationsLoop()24         public void TestContinuationsLoop()
25         {
26             Continuation _contA = new Continuation();
27 
28             _contA.Mark();
29             int value = 0;
30             int ret = _contA.Store(0);
31             for (int i = ret; i < 10; i++) {
32                 value += i;
33             }
34 
35             if (value > 0) {
36                 total += value;
37                 _contA.Restore(ret + 1);
38             }
39 
40             Assert.AreEqual(total, 330);
41         }
42 
43         private int yields = 0;
44 
45         [Test]
Yielding()46         public void Yielding()
47         {
48             Continuation baseCont = new Continuation();
49             Continuation taskCont = new Continuation();
50 
51             baseCont.Mark();
52             taskCont.Mark();
53 
54             // Store the base continuation to start the task
55             if (baseCont.Store(0) == 0) {
56                 bool done = false;
57                 int count = 0;
58 
59                 while (!done) {
60                     // Do stuff for the task.
61                     ++count;
62 
63                     // This task is counting to 100.
64                     if (count == 100) {
65                         done = true;
66                     }
67 
68                     // Yield every 10 loops
69                     else if (count % 10 == 0) {
70 
71                         // To yield, store the task continuation then restore
72                         // the base continuation.
73                         if (taskCont.Store(0) == 0) {
74                             baseCont.Restore(1);
75                         }
76                     }
77                 }
78             }
79             // When restored, 'Store' will return what was passed to Restore, in this case 1 so fall here.
80             else {
81                 // Count the yields, then go back to the task.
82                 ++yields;
83                 taskCont.Restore(1);
84             }
85 
86             Assert.AreEqual(9, yields);
87         }
88 
89 
90         public class MicroThread
91         {
92 
Yield()93             public void Yield()
94             {
95                 if (MyThread.Store(0) == 0) {
96                     MainThread.Restore(1);
97                 }
98             }
99 
Resume()100             public void Resume()
101             {
102                 if (MainThread.Store(0) == 0) {
103                     MyThread.Restore(1);
104                 }
105             }
106 
DoWork(Action action)107             public void DoWork(Action action)
108             {
109                 if (MainThread.Store(0) == 0) {
110                     action();
111                     Done = true;
112                     MainThread.Restore(1);
113                 }
114             }
115 
116             public bool Done = false;
117             public Continuation MainThread = new Continuation();
118             public Continuation MyThread = new Continuation();
119         }
120 
121         public class MicroBJob
122         {
123             private int _Count = 0;
124             public int Count
125             {
126                 get { return _Count; }
127                 set { _Count = value; }
128             }
129 
130             public MicroThread MicroThread;
Work()131             public void Work()
132             {
133                 while (Count < 100) {
134                     ++Count;
135                     if (Count % 10 == 0) {
136                         MicroThread.Yield();
137                     }
138                 }
139             }
140         }
141 
142         [Test]
MicroThreadTest()143         public void MicroThreadTest()
144         {
145             MicroThread microA = new MicroThread();
146             MicroThread microB = new MicroThread();
147 
148             microA.MainThread.Mark();
149             microA.MyThread.Mark();
150             microB.MainThread.Mark();
151             microB.MyThread.Mark();
152 
153             Assert.AreEqual(false, microA.Done);
154             Assert.AreEqual(false, microB.Done);
155 
156             microA.DoWork(() =>
157             {
158                 int count = 0;
159                 while (count < 100) {
160                     ++count;
161                     if (count % 10 == 0) {
162                         microA.Yield();
163                     }
164                 }
165             });
166 
167             MicroBJob jobB = new MicroBJob();
168             jobB.MicroThread = microB;
169 
170             microB.DoWork(jobB.Work);
171 
172             Assert.AreEqual(false, microA.Done);
173             Assert.AreEqual(false, microB.Done);
174 
175             int yields = 0;
176             while (yields < 20) {
177                 if (!microA.Done) microA.Resume();
178                 if (!microB.Done) microB.Resume();
179                 if (microA.Done && microB.Done) break;
180                 ++yields;
181             }
182 
183             Assert.AreEqual(true, microA.Done);
184             Assert.AreEqual(true, microB.Done);
185             Assert.AreEqual(100, jobB.Count);
186             Assert.AreEqual(9, yields);
187         }
188     }
189 }
190