xref: /reactos/modules/rostests/tests/fiber/fiber.c (revision c2c66aff)
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