1*c2c66affSColin Finck #include <assert.h>
2*c2c66affSColin Finck #include <limits.h>
3*c2c66affSColin Finck #include <stdio.h>
4*c2c66affSColin Finck #include <stdlib.h>
5*c2c66affSColin Finck #include <time.h>
6*c2c66affSColin Finck
7*c2c66affSColin Finck #include <tchar.h>
8*c2c66affSColin Finck #include <windows.h>
9*c2c66affSColin Finck
10*c2c66affSColin Finck #ifndef InitializeListHead
11*c2c66affSColin Finck #define InitializeListHead(PLH__) ((PLH__)->Flink = (PLH__)->Blink = (PLH__))
12*c2c66affSColin Finck #endif
13*c2c66affSColin Finck
14*c2c66affSColin Finck #ifndef IsListEmpty
15*c2c66affSColin Finck #define IsListEmpty(PLH__) ((PLH__)->Flink == (PVOID)(PLH__))
16*c2c66affSColin Finck #endif
17*c2c66affSColin Finck
18*c2c66affSColin Finck #ifndef RemoveEntryList
19*c2c66affSColin Finck
20*c2c66affSColin Finck #define RemoveEntryList(PLE__) \
21*c2c66affSColin Finck { \
22*c2c66affSColin Finck PLIST_ENTRY pleBack__ = (PLIST_ENTRY)((PLE__)->Blink); \
23*c2c66affSColin Finck PLIST_ENTRY pleForward__ = (PLIST_ENTRY)((PLE__)->Flink); \
24*c2c66affSColin Finck \
25*c2c66affSColin Finck pleBack__->Flink = pleForward__; \
26*c2c66affSColin Finck pleForward__->Blink = pleBack__; \
27*c2c66affSColin Finck }
28*c2c66affSColin Finck
29*c2c66affSColin Finck #endif
30*c2c66affSColin Finck
31*c2c66affSColin Finck #ifndef InsertTailList
32*c2c66affSColin Finck
33*c2c66affSColin Finck #define InsertTailList(PLH__, PLE__) \
34*c2c66affSColin Finck { \
35*c2c66affSColin Finck PLIST_ENTRY pleListHead__ = (PLH__); \
36*c2c66affSColin Finck PLIST_ENTRY pleBlink__ = (PLIST_ENTRY)((PLH__)->Blink); \
37*c2c66affSColin Finck \
38*c2c66affSColin Finck (PLE__)->Flink = pleListHead__; \
39*c2c66affSColin Finck (PLE__)->Blink = pleBlink__; \
40*c2c66affSColin Finck pleBlink__->Flink = (PLE__); \
41*c2c66affSColin Finck pleListHead__->Blink = (PLE__); \
42*c2c66affSColin Finck }
43*c2c66affSColin Finck
44*c2c66affSColin Finck #endif
45*c2c66affSColin Finck
46*c2c66affSColin Finck #ifndef RemoveHeadList
47*c2c66affSColin Finck
48*c2c66affSColin Finck #define RemoveHeadList(PLH__) \
49*c2c66affSColin Finck (PLIST_ENTRY)((PLH__)->Flink); \
50*c2c66affSColin Finck RemoveEntryList((PLIST_ENTRY)((PLH__)->Flink));
51*c2c66affSColin Finck
52*c2c66affSColin Finck #endif
53*c2c66affSColin Finck
54*c2c66affSColin Finck #define FIBERTEST_COUNT 500
55*c2c66affSColin Finck
56*c2c66affSColin Finck struct FiberData
57*c2c66affSColin Finck {
58*c2c66affSColin Finck unsigned nMagic;
59*c2c66affSColin Finck unsigned nId;
60*c2c66affSColin Finck unsigned nPrio;
61*c2c66affSColin Finck unsigned nRealPrio;
62*c2c66affSColin Finck PVOID pFiber;
63*c2c66affSColin Finck LIST_ENTRY leQueue;
64*c2c66affSColin Finck int nQuantumQueued;
65*c2c66affSColin Finck int nBoost;
66*c2c66affSColin Finck struct FiberData * pfdPrev;
67*c2c66affSColin Finck int bExitPrev;
68*c2c66affSColin Finck };
69*c2c66affSColin Finck
70*c2c66affSColin Finck static LIST_ENTRY a_leQueues[32];
71*c2c66affSColin Finck static unsigned nQuantum = 0;
72*c2c66affSColin Finck static struct FiberData * pfdLastStarveScan = NULL;
73*c2c66affSColin Finck
74*c2c66affSColin Finck void Fbt_Create(int);
75*c2c66affSColin Finck void Fbt_Exit(void);
76*c2c66affSColin Finck void Fbt_Yield(void);
77*c2c66affSColin Finck
78*c2c66affSColin Finck struct FiberData * Fbt_GetCurrent(void);
79*c2c66affSColin Finck unsigned Fbt_GetCurrentId(void);
80*c2c66affSColin Finck VOID CALLBACK Fbt_Startup(PVOID);
81*c2c66affSColin Finck void Fbt_Dispatch(struct FiberData *, int);
82*c2c66affSColin Finck void Fbt_AfterSwitch(struct FiberData *);
83*c2c66affSColin Finck
84*c2c66affSColin Finck void DoStuff(void);
85*c2c66affSColin Finck
Fbt_GetCurrent(VOID)86*c2c66affSColin Finck struct FiberData * Fbt_GetCurrent(VOID)
87*c2c66affSColin Finck {
88*c2c66affSColin Finck return GetFiberData();
89*c2c66affSColin Finck }
90*c2c66affSColin Finck
Fbt_GetCurrentId(VOID)91*c2c66affSColin Finck unsigned Fbt_GetCurrentId(VOID)
92*c2c66affSColin Finck {
93*c2c66affSColin Finck return Fbt_GetCurrent()->nId;
94*c2c66affSColin Finck }
95*c2c66affSColin Finck
Fbt_Yield(VOID)96*c2c66affSColin Finck void Fbt_Yield(VOID)
97*c2c66affSColin Finck {
98*c2c66affSColin Finck struct FiberData * pfdCur;
99*c2c66affSColin Finck
100*c2c66affSColin Finck pfdCur = Fbt_GetCurrent();
101*c2c66affSColin Finck
102*c2c66affSColin Finck if(pfdCur->nBoost)
103*c2c66affSColin Finck {
104*c2c66affSColin Finck -- pfdCur->nBoost;
105*c2c66affSColin Finck
106*c2c66affSColin Finck if(!pfdCur->nBoost)
107*c2c66affSColin Finck pfdCur->nPrio = pfdCur->nRealPrio;
108*c2c66affSColin Finck }
109*c2c66affSColin Finck else if((rand() % 100) > 50 - (45 * pfdCur->nPrio) / 32)
110*c2c66affSColin Finck Fbt_Dispatch(pfdCur, 0);
111*c2c66affSColin Finck }
112*c2c66affSColin Finck
Fbt_AfterSwitch(struct FiberData * pfdCur)113*c2c66affSColin Finck void Fbt_AfterSwitch(struct FiberData * pfdCur)
114*c2c66affSColin Finck {
115*c2c66affSColin Finck struct FiberData * pfdPrev;
116*c2c66affSColin Finck
117*c2c66affSColin Finck pfdPrev = pfdCur->pfdPrev;
118*c2c66affSColin Finck
119*c2c66affSColin Finck /* The previous fiber left some homework for us */
120*c2c66affSColin Finck if(pfdPrev)
121*c2c66affSColin Finck {
122*c2c66affSColin Finck /* Kill the predecessor */
123*c2c66affSColin Finck if(pfdCur->bExitPrev)
124*c2c66affSColin Finck {
125*c2c66affSColin Finck if(pfdLastStarveScan == pfdPrev)
126*c2c66affSColin Finck pfdLastStarveScan = 0;
127*c2c66affSColin Finck
128*c2c66affSColin Finck DeleteFiber(pfdPrev->pFiber);
129*c2c66affSColin Finck free(pfdPrev);
130*c2c66affSColin Finck }
131*c2c66affSColin Finck /* Enqueue the previous fiber in the correct ready queue */
132*c2c66affSColin Finck else
133*c2c66affSColin Finck {
134*c2c66affSColin Finck /* Remember the quantum in which the previous fiber was queued */
135*c2c66affSColin Finck pfdPrev->nQuantumQueued = nQuantum;
136*c2c66affSColin Finck
137*c2c66affSColin Finck /* Disable the anti-starvation boost */
138*c2c66affSColin Finck if(pfdPrev->nBoost)
139*c2c66affSColin Finck {
140*c2c66affSColin Finck pfdPrev->nBoost = 0;
141*c2c66affSColin Finck pfdPrev->nPrio = pfdPrev->nRealPrio;
142*c2c66affSColin Finck }
143*c2c66affSColin Finck
144*c2c66affSColin Finck /* Enqueue the previous fiber */
145*c2c66affSColin Finck InsertTailList
146*c2c66affSColin Finck (
147*c2c66affSColin Finck &a_leQueues[pfdPrev->nPrio],
148*c2c66affSColin Finck &pfdPrev->leQueue
149*c2c66affSColin Finck );
150*c2c66affSColin Finck }
151*c2c66affSColin Finck }
152*c2c66affSColin Finck }
153*c2c66affSColin Finck
Fbt_Startup(PVOID pParam)154*c2c66affSColin Finck VOID CALLBACK Fbt_Startup(PVOID pParam)
155*c2c66affSColin Finck {
156*c2c66affSColin Finck assert(pParam == GetFiberData());
157*c2c66affSColin Finck Fbt_AfterSwitch(pParam);
158*c2c66affSColin Finck DoStuff();
159*c2c66affSColin Finck Fbt_Exit();
160*c2c66affSColin Finck }
161*c2c66affSColin Finck
Fbt_Dispatch(struct FiberData * pfdCur,int bExit)162*c2c66affSColin Finck void Fbt_Dispatch(struct FiberData * pfdCur, int bExit)
163*c2c66affSColin Finck {
164*c2c66affSColin Finck UCHAR i;
165*c2c66affSColin Finck UCHAR n;
166*c2c66affSColin Finck struct FiberData * pfdNext;
167*c2c66affSColin Finck
168*c2c66affSColin Finck assert(pfdCur == GetFiberData());
169*c2c66affSColin Finck
170*c2c66affSColin Finck ++ nQuantum;
171*c2c66affSColin Finck
172*c2c66affSColin Finck /* Every ten quantums check for starving threads */
173*c2c66affSColin Finck /* FIXME: this implementation of starvation prevention isn't that great */
174*c2c66affSColin Finck if(nQuantum % 10 == 0)
175*c2c66affSColin Finck {
176*c2c66affSColin Finck int j;
177*c2c66affSColin Finck int k;
178*c2c66affSColin Finck int b;
179*c2c66affSColin Finck int bResume;
180*c2c66affSColin Finck PLIST_ENTRY ple = NULL;
181*c2c66affSColin Finck
182*c2c66affSColin Finck bResume = 0;
183*c2c66affSColin Finck i = 0;
184*c2c66affSColin Finck
185*c2c66affSColin Finck /* Pick up from where we left last time */
186*c2c66affSColin Finck if(pfdLastStarveScan)
187*c2c66affSColin Finck {
188*c2c66affSColin Finck unsigned nPrio;
189*c2c66affSColin Finck
190*c2c66affSColin Finck nPrio = pfdLastStarveScan->nPrio;
191*c2c66affSColin Finck
192*c2c66affSColin Finck /* The last fiber we scanned for starvation isn't queued anymore */
193*c2c66affSColin Finck if(IsListEmpty(&pfdLastStarveScan->leQueue))
194*c2c66affSColin Finck /* Scan the ready queue for its priority */
195*c2c66affSColin Finck i = nPrio;
196*c2c66affSColin Finck /* Last fiber for its priority level */
197*c2c66affSColin Finck else if(pfdLastStarveScan->leQueue.Flink == &a_leQueues[nPrio])
198*c2c66affSColin Finck /* Scan the ready queue for the next priority level */
199*c2c66affSColin Finck i = nPrio + 1;
200*c2c66affSColin Finck /* Scan the next fiber in the ready queue */
201*c2c66affSColin Finck else
202*c2c66affSColin Finck {
203*c2c66affSColin Finck i = nPrio;
204*c2c66affSColin Finck ple = pfdLastStarveScan->leQueue.Flink;
205*c2c66affSColin Finck bResume = 1;
206*c2c66affSColin Finck }
207*c2c66affSColin Finck
208*c2c66affSColin Finck /* Priority levels 15-31 are never checked for starvation */
209*c2c66affSColin Finck if(i >= 15)
210*c2c66affSColin Finck {
211*c2c66affSColin Finck if(bResume)
212*c2c66affSColin Finck bResume = 0;
213*c2c66affSColin Finck
214*c2c66affSColin Finck i = 0;
215*c2c66affSColin Finck }
216*c2c66affSColin Finck }
217*c2c66affSColin Finck
218*c2c66affSColin Finck /*
219*c2c66affSColin Finck Scan at most 16 threads, in the priority range 0-14, applying in total at
220*c2c66affSColin Finck most 10 boosts. This loop scales O(1)
221*c2c66affSColin Finck */
222*c2c66affSColin Finck for(j = 0, k = 0, b = 0; j < 16 && k < 15 && b < 10; ++ j)
223*c2c66affSColin Finck {
224*c2c66affSColin Finck unsigned nDiff;
225*c2c66affSColin Finck
226*c2c66affSColin Finck /* No previous state to resume from */
227*c2c66affSColin Finck if(!bResume)
228*c2c66affSColin Finck {
229*c2c66affSColin Finck int nQueue;
230*c2c66affSColin Finck
231*c2c66affSColin Finck /* Get the first element in the current queue */
232*c2c66affSColin Finck nQueue = (k + i) % 15;
233*c2c66affSColin Finck
234*c2c66affSColin Finck if(IsListEmpty(&a_leQueues[nQueue]))
235*c2c66affSColin Finck {
236*c2c66affSColin Finck ++ k;
237*c2c66affSColin Finck continue;
238*c2c66affSColin Finck }
239*c2c66affSColin Finck
240*c2c66affSColin Finck ple = (PLIST_ENTRY)a_leQueues[nQueue].Flink;
241*c2c66affSColin Finck }
242*c2c66affSColin Finck else
243*c2c66affSColin Finck bResume = 0;
244*c2c66affSColin Finck
245*c2c66affSColin Finck /* Get the current fiber */
246*c2c66affSColin Finck pfdLastStarveScan = CONTAINING_RECORD(ple, struct FiberData, leQueue);
247*c2c66affSColin Finck assert(pfdLastStarveScan->nMagic == 0x12345678);
248*c2c66affSColin Finck assert(pfdLastStarveScan != pfdCur);
249*c2c66affSColin Finck
250*c2c66affSColin Finck /* Calculate the number of quantums the fiber has been in the queue */
251*c2c66affSColin Finck if(nQuantum > pfdLastStarveScan->nQuantumQueued)
252*c2c66affSColin Finck nDiff = nQuantum - pfdLastStarveScan->nQuantumQueued;
253*c2c66affSColin Finck else
254*c2c66affSColin Finck nDiff = UINT_MAX - pfdLastStarveScan->nQuantumQueued + nQuantum;
255*c2c66affSColin Finck
256*c2c66affSColin Finck /* The fiber has been ready for more than 30 quantums: it's starving */
257*c2c66affSColin Finck if(nDiff > 30)
258*c2c66affSColin Finck {
259*c2c66affSColin Finck /* Plus one boost applied */
260*c2c66affSColin Finck ++ b;
261*c2c66affSColin Finck
262*c2c66affSColin Finck /* Apply the boost */
263*c2c66affSColin Finck pfdLastStarveScan->nBoost = 1;
264*c2c66affSColin Finck pfdLastStarveScan->nRealPrio = pfdLastStarveScan->nPrio;
265*c2c66affSColin Finck pfdLastStarveScan->nPrio = 15;
266*c2c66affSColin Finck
267*c2c66affSColin Finck /* Re-enqueue the fiber in the correct priority queue */
268*c2c66affSColin Finck RemoveEntryList(&pfdLastStarveScan->leQueue);
269*c2c66affSColin Finck InsertTailList(&a_leQueues[15], &pfdLastStarveScan->leQueue);
270*c2c66affSColin Finck }
271*c2c66affSColin Finck }
272*c2c66affSColin Finck }
273*c2c66affSColin Finck
274*c2c66affSColin Finck pfdNext = NULL;
275*c2c66affSColin Finck
276*c2c66affSColin Finck /* This fiber is going to die: scan all ready queues */
277*c2c66affSColin Finck if(bExit)
278*c2c66affSColin Finck n = 1;
279*c2c66affSColin Finck /*
280*c2c66affSColin Finck Scan only ready queues for priorities greater than or equal to the priority of
281*c2c66affSColin Finck the current thread (round-robin)
282*c2c66affSColin Finck */
283*c2c66affSColin Finck else
284*c2c66affSColin Finck n = pfdCur->nPrio + 1;
285*c2c66affSColin Finck
286*c2c66affSColin Finck /* This loop scales O(1) */
287*c2c66affSColin Finck for(i = 32; i >= n; -- i)
288*c2c66affSColin Finck {
289*c2c66affSColin Finck PLIST_ENTRY pleNext;
290*c2c66affSColin Finck
291*c2c66affSColin Finck /* No fiber ready for this priority level */
292*c2c66affSColin Finck if(IsListEmpty(&a_leQueues[i - 1]))
293*c2c66affSColin Finck continue;
294*c2c66affSColin Finck
295*c2c66affSColin Finck /* Get the next ready fiber */
296*c2c66affSColin Finck pleNext = RemoveHeadList(&a_leQueues[i - 1]);
297*c2c66affSColin Finck InitializeListHead(pleNext);
298*c2c66affSColin Finck pfdNext = CONTAINING_RECORD(pleNext, struct FiberData, leQueue);
299*c2c66affSColin Finck assert(pfdNext->pFiber != GetCurrentFiber());
300*c2c66affSColin Finck assert(pfdNext->nMagic == 0x12345678);
301*c2c66affSColin Finck break;
302*c2c66affSColin Finck }
303*c2c66affSColin Finck
304*c2c66affSColin Finck /* Next fiber chosen */
305*c2c66affSColin Finck if(pfdNext)
306*c2c66affSColin Finck {
307*c2c66affSColin Finck /* Give some homework to the next fiber */
308*c2c66affSColin Finck pfdNext->pfdPrev = pfdCur;
309*c2c66affSColin Finck pfdNext->bExitPrev = bExit;
310*c2c66affSColin Finck
311*c2c66affSColin Finck /* Switch to the next fiber */
312*c2c66affSColin Finck SwitchToFiber(pfdNext->pFiber);
313*c2c66affSColin Finck
314*c2c66affSColin Finck /* Complete the switch back to this fiber */
315*c2c66affSColin Finck Fbt_AfterSwitch(pfdCur);
316*c2c66affSColin Finck }
317*c2c66affSColin Finck /* No next fiber, and current fiber exiting */
318*c2c66affSColin Finck else if(bExit)
319*c2c66affSColin Finck {
320*c2c66affSColin Finck PVOID pCurFiber;
321*c2c66affSColin Finck
322*c2c66affSColin Finck /* Delete the current fiber. This kills the thread and stops the simulation */
323*c2c66affSColin Finck if(pfdLastStarveScan == pfdCur)
324*c2c66affSColin Finck pfdLastStarveScan = NULL;
325*c2c66affSColin Finck
326*c2c66affSColin Finck pCurFiber = pfdCur->pFiber;
327*c2c66affSColin Finck free(pfdCur);
328*c2c66affSColin Finck DeleteFiber(pCurFiber);
329*c2c66affSColin Finck }
330*c2c66affSColin Finck /* No next fiber: continue running the current one */
331*c2c66affSColin Finck }
332*c2c66affSColin Finck
Fbt_Exit(VOID)333*c2c66affSColin Finck void Fbt_Exit(VOID)
334*c2c66affSColin Finck {
335*c2c66affSColin Finck Fbt_Dispatch(GetFiberData(), 1);
336*c2c66affSColin Finck }
337*c2c66affSColin Finck
Fbt_CreateFiber(int bInitial)338*c2c66affSColin Finck void Fbt_CreateFiber(int bInitial)
339*c2c66affSColin Finck {
340*c2c66affSColin Finck PVOID pFiber;
341*c2c66affSColin Finck struct FiberData * pData;
342*c2c66affSColin Finck static int s_bFiberPrioSeeded = 0;
343*c2c66affSColin Finck static LONG s_nFiberIdSeed = 0;
344*c2c66affSColin Finck
345*c2c66affSColin Finck pData = malloc(sizeof(struct FiberData));
346*c2c66affSColin Finck
347*c2c66affSColin Finck assert(pData);
348*c2c66affSColin Finck
349*c2c66affSColin Finck if(bInitial)
350*c2c66affSColin Finck pFiber = ConvertThreadToFiber(pData);
351*c2c66affSColin Finck else
352*c2c66affSColin Finck pFiber = CreateFiber(0, Fbt_Startup, pData);
353*c2c66affSColin Finck
354*c2c66affSColin Finck if(!s_bFiberPrioSeeded)
355*c2c66affSColin Finck {
356*c2c66affSColin Finck unsigned nFiberPrioSeed;
357*c2c66affSColin Finck time_t tCurTime;
358*c2c66affSColin Finck
359*c2c66affSColin Finck tCurTime = time(NULL);
360*c2c66affSColin Finck memcpy(&nFiberPrioSeed, &tCurTime, sizeof(nFiberPrioSeed));
361*c2c66affSColin Finck srand(nFiberPrioSeed);
362*c2c66affSColin Finck s_bFiberPrioSeeded = 1;
363*c2c66affSColin Finck }
364*c2c66affSColin Finck
365*c2c66affSColin Finck assert(pFiber);
366*c2c66affSColin Finck
367*c2c66affSColin Finck pData->nMagic = 0x12345678;
368*c2c66affSColin Finck pData->nId = InterlockedIncrement(&s_nFiberIdSeed);
369*c2c66affSColin Finck pData->nPrio = rand() % 32;
370*c2c66affSColin Finck pData->pFiber = pFiber;
371*c2c66affSColin Finck pData->nQuantumQueued = 0;
372*c2c66affSColin Finck pData->nBoost = 0;
373*c2c66affSColin Finck pData->nRealPrio = pData->nPrio;
374*c2c66affSColin Finck pData->pfdPrev = NULL;
375*c2c66affSColin Finck pData->bExitPrev = 0;
376*c2c66affSColin Finck
377*c2c66affSColin Finck if(bInitial)
378*c2c66affSColin Finck {
379*c2c66affSColin Finck InitializeListHead(&pData->leQueue);
380*c2c66affSColin Finck }
381*c2c66affSColin Finck else
382*c2c66affSColin Finck {
383*c2c66affSColin Finck InsertTailList
384*c2c66affSColin Finck (
385*c2c66affSColin Finck &a_leQueues[pData->nPrio],
386*c2c66affSColin Finck &pData->leQueue
387*c2c66affSColin Finck );
388*c2c66affSColin Finck }
389*c2c66affSColin Finck }
390*c2c66affSColin Finck
DoStuff(void)391*c2c66affSColin Finck void DoStuff(void)
392*c2c66affSColin Finck {
393*c2c66affSColin Finck unsigned i;
394*c2c66affSColin Finck unsigned n;
395*c2c66affSColin Finck unsigned nId;
396*c2c66affSColin Finck
397*c2c66affSColin Finck n = rand() % 1000;
398*c2c66affSColin Finck nId = Fbt_GetCurrentId();
399*c2c66affSColin Finck
400*c2c66affSColin Finck _ftprintf(stderr, _T("[%u] BEGIN\n"), nId);
401*c2c66affSColin Finck
402*c2c66affSColin Finck for(i = 0; i < n; ++ i)
403*c2c66affSColin Finck {
404*c2c66affSColin Finck unsigned j;
405*c2c66affSColin Finck unsigned m;
406*c2c66affSColin Finck
407*c2c66affSColin Finck _ftprintf(stderr, _T("[%u] [%u/%u]\n"), nId, i + 1, n);
408*c2c66affSColin Finck
409*c2c66affSColin Finck m = rand() % 1000;
410*c2c66affSColin Finck
411*c2c66affSColin Finck for(j = 0; j < m; ++ j)
412*c2c66affSColin Finck Sleep(0);
413*c2c66affSColin Finck
414*c2c66affSColin Finck Fbt_Yield();
415*c2c66affSColin Finck }
416*c2c66affSColin Finck
417*c2c66affSColin Finck _ftprintf(stderr, _T("[%u] END\n"), nId);
418*c2c66affSColin Finck }
419*c2c66affSColin Finck
_tmain(int argc,_TCHAR const * const * argv)420*c2c66affSColin Finck int _tmain(int argc, _TCHAR const * const * argv)
421*c2c66affSColin Finck {
422*c2c66affSColin Finck unsigned i;
423*c2c66affSColin Finck unsigned nFibers;
424*c2c66affSColin Finck
425*c2c66affSColin Finck if(argc > 1)
426*c2c66affSColin Finck nFibers = _tcstoul(argv[1], NULL, 0);
427*c2c66affSColin Finck else
428*c2c66affSColin Finck nFibers = FIBERTEST_COUNT;
429*c2c66affSColin Finck
430*c2c66affSColin Finck for(i = 0; i < 32; ++ i)
431*c2c66affSColin Finck {
432*c2c66affSColin Finck InitializeListHead(&a_leQueues[i]);
433*c2c66affSColin Finck }
434*c2c66affSColin Finck
435*c2c66affSColin Finck for(i = 0; i < nFibers; ++ i)
436*c2c66affSColin Finck Fbt_CreateFiber(i == 0);
437*c2c66affSColin Finck
438*c2c66affSColin Finck Fbt_Startup(GetFiberData());
439*c2c66affSColin Finck
440*c2c66affSColin Finck return 0;
441*c2c66affSColin Finck }
442*c2c66affSColin Finck
443*c2c66affSColin Finck /* EOF */
444