windows-torture-test-20060625
[openafs.git] / src / WINNT / tests / torture / Source / WinTorture.c
1 //#define _WIN32_WINNT 0x0500
2 //#include <windows.h>
3
4 #include "includes.h"
5 #include <Psapi.h>
6 #include "common.h"
7 #ifdef HAVE_HESOID
8     #include "ResolveLocker.h"
9     extern int ResolveLocker(USER_OPTIONS *attachOption);
10     extern void GetLockerInfo(char *Locker, char *Path);
11 #endif /* HAVE_HESOID */
12
13 #define MAX_THREADS 100
14
15 int opterr = 1;
16 int optind = 1;
17 int optopt;
18 int optreset;
19 char *optarg;
20
21 extern void LogStats(char *FileName, int ToLog, int Iteration,  int NumberOfProcesses, int NumberOfThreads, 
22                      char *HostName, int ProcessNumber, struct cmd_struct CommandInfo[],
23                      char *CommandLine, char *TargetDirectory);
24 extern int UpdateMasterLog(char *FileName, struct cmd_struct CommandInfo[]);
25 extern int BuildMasterStatLog(char *FileName, char *MoveFileName, int NumberOfProcesses, 
26                               int NumberOfThreads, char *CommandLine, int LoopCount, 
27                               char *TargetDirectory, int ProcessNumber);
28 extern void LogMessage(int ProcessNumber, char *HostName, char *FileName, char *message, int LogID);
29
30 DWORD WINAPI StressTestThread(LPVOID lpThreadParameter);
31 int   getopt(int, char**, char*);
32 DWORD FindProcessCount(char *ProcessName, HANDLE JobHandle);
33 void  show_results(char *CommandLine, char *TargetDirectory, struct cmd_struct CommandInfo[], 
34                    char *HostName, int NumberOfThreads, int CurrentLoop, int LogID);
35
36 char    *ClientText = "streamfiles.txt";
37 char    PathToSecondDir[256];
38 int     ThreadStatus[MAX_HANDLES];
39 int     verbose;
40 int     BufferSize = 256*1024;
41 int     UseLocker = 0;
42 //int     UseUnicode = 0;
43 int     EndOnError;
44 int     AfsTrace;
45 int     ChronLog;
46 BOOL    PrintStats;
47 HANDLE  MutexHandle;
48 HANDLE  FileMutexHandle;
49 HANDLE  ChronMutexHandle;
50 HANDLE  OSMutexHandle;
51 HANDLE  ShutDownEventHandle;
52 HANDLE  PauseEventHandle;
53 HANDLE  ContinueEventHandle;
54 EXIT_STATUS ExitStatus[MAX_HANDLES];
55
56 double create_procs(char *Hostname, char *CommandLine, char *TargetDirectory, 
57                     char *AfsLocker, char *Locker, char *HostName, 
58                     int NumberOfThreads, int CurrentLoop, int LogID)
59 {
60     int     i;
61     int     status;
62     int     count;
63     int     ProcessID;
64     char    EventName[512];
65     HANDLE  hEventHandle[MAX_HANDLES];
66     HANDLE  hThreadHandle[MAX_HANDLES];
67     DWORD   dwThreadID[MAX_HANDLES];
68     struct cmd_struct *CommandInfo;
69     CRITICAL_SECTION CriticalSection;
70     PARAMETERLIST    *pParameterList[MAX_HANDLES];
71 #ifdef HAVE_HESOID
72     USER_OPTIONS     attachOption;
73 #endif
74
75     InitializeCriticalSection(&CriticalSection); 
76     for (i = 0; i < MAX_HANDLES; i++)
77     {
78         hEventHandle[i] = NULL;
79         hThreadHandle[i] = NULL;
80         pParameterList[i] = NULL;
81         dwThreadID[i] = 0;
82     }
83
84     count = 0;
85     CommandInfo = calloc(1, sizeof(struct cmd_struct) * (CMD_MAX_CMD + 1) * NumberOfThreads);
86     ProcessID = getpid();
87
88     for (i = 0; i < NumberOfThreads; i++) 
89     {
90         if (EndOnError)
91         {
92             if (ThreadStatus[count] == 0)
93                 continue;
94         }
95         sprintf(EventName, "%d%sEvent%05d", ProcessID, HostName, count);
96         hEventHandle[count] = CreateEvent(NULL, FALSE, FALSE, EventName);
97         if (hEventHandle[count] == NULL)
98             continue;
99         ResetEvent(hEventHandle[count]);
100         
101         pParameterList[count] = calloc(1, sizeof(PARAMETERLIST));
102         pParameterList[count]->ProcessNumber = count;
103         pParameterList[count]->CommandInfo = (struct cmd_struct *)(CommandInfo + (i * (CMD_MAX_CMD + 1)));
104         pParameterList[count]->BufferSize = BufferSize;
105         pParameterList[count]->PrintStats = PrintStats;
106         pParameterList[count]->CurrentLoop = CurrentLoop;
107         pParameterList[count]->AfsTrace = AfsTrace;
108         pParameterList[count]->TargetDirectory = TargetDirectory;
109         pParameterList[count]->pExitStatus = &ExitStatus[i];
110         pParameterList[count]->pThreadStatus = &ThreadStatus[i];
111         pParameterList[count]->CommandLine = CommandLine;
112         pParameterList[count]->ClientText = ClientText;
113         pParameterList[count]->PathToSecondDir = PathToSecondDir;
114         pParameterList[count]->AfsLocker = AfsLocker;
115         pParameterList[count]->HostName = HostName;
116         pParameterList[count]->ProcessID = ProcessID;;
117         pParameterList[count]->LogID = LogID;;
118
119         ThreadStatus[count] = 0;
120         hThreadHandle[count] = CreateThread(NULL, 0, &StressTestThread, (LPVOID)pParameterList[count], CREATE_SUSPENDED, &dwThreadID[count]);
121         if (hThreadHandle[count] != NULL)
122         {
123             ResumeThread(hThreadHandle[count]);
124             ThreadStatus[count] = 1;
125             ++count;
126         }
127         else
128         {
129             CloseHandle(hEventHandle[count]);
130             if (pParameterList[count] != NULL)
131                 free(pParameterList[count]);
132             pParameterList[count] = NULL;
133             hThreadHandle[count] = NULL;
134             hEventHandle[count] = NULL;
135         }
136     }
137
138     count = 0;
139     for (i = 0; i < MAX_HANDLES; i++)
140     {
141         if (hEventHandle[i] != NULL)
142             ++count;
143     }
144 #ifdef HAVE_HESOID
145     if (UseLocker)
146     {
147         int          rc;
148
149         memset(&attachOption, '\0', sizeof(attachOption));
150         strcpy(attachOption.Locker, Locker);
151         strcpy(attachOption.type, "locker");
152         if (rc = ResolveLocker(&attachOption))
153         {
154             if (!stricmp(attachOption.type, "AFS"))
155             {
156                 printf("Unable to attach locker %s - AFS is not supported\n", Locker);
157                 exit(1);
158             }
159             strcpy(AfsLocker, attachOption.SubMount);
160             memset(&attachOption, '\0', sizeof(attachOption));
161             strcpy(attachOption.Locker, Locker);
162             strcpy(attachOption.type, "locker");
163             if (rc = attach(attachOption, 0, 0, Locker))
164             {
165                 printf("Unable to attach locker %s\n", Locker);
166                 exit(1);
167             }
168         }
169     }
170 #endif /* HAVE_HESOID */
171
172     status = WaitForMultipleObjects(count, hEventHandle, TRUE, INFINITE);
173     for (i = 0; i < MAX_HANDLES; i++)
174     {
175         if (hEventHandle[i] != NULL)
176             CloseHandle(hEventHandle[i]);
177         if (pParameterList[i] != NULL)
178             free(pParameterList[i]);
179         pParameterList[i] = NULL;
180         hEventHandle[i] = NULL;
181     }
182
183     for (i = 0; i < NumberOfThreads; i++)
184     {
185         char    FileName[128];
186         char    temp[512];
187
188         if (strlen(ExitStatus[i].Reason))
189         {
190             sprintf(temp, "Thread %0d exited with reason: %s", i, ExitStatus[i].Reason);
191         }
192         else
193         {
194             sprintf(temp, "Thread %0d completed\n", i);
195         }
196         if (verbose)
197             printf("%s", temp);
198         sprintf(FileName, "Thread_%05d.log", i);
199         LogMessage(i, HostName, FileName, temp, LogID);
200         sprintf(temp, "Ended Iteration %0d\n\n", CurrentLoop);
201         LogMessage(i, HostName, FileName, temp, LogID);
202         CloseHandle(hEventHandle[i]);
203     }
204     show_results(CommandLine, TargetDirectory, CommandInfo, HostName, NumberOfThreads, CurrentLoop, LogID);
205     free(CommandInfo);
206     DeleteCriticalSection(&CriticalSection);
207
208     return(0);
209 }
210
211 static void usage(void)
212 {
213
214     fprintf(stderr, "usage: wintorture [options]\n");
215     fprintf(stderr, "where options can be:\n");
216     fprintf(stderr, "\t-b        Create a chronological log.\n");
217     fprintf(stderr, "\t-c <txt>  Specifies the script txt file to use.\n");
218     fprintf(stderr, "\t-e        End thread processing on an error.\n");
219     fprintf(stderr, "\t-f <name> Target directory name.\n");
220     fprintf(stderr, "\t-i <num>  Number of iterations of the stress test to run.\n");
221     fprintf(stderr, "\t            This option will override the -m option.\n");
222 #ifdef HAVE_HESOID
223     fprintf(stderr, "\t-l <path> AFS locker or AFS submount in which to create the target directory.\n");
224 #endif /* HAVE_HESOID */
225     fprintf(stderr, "\t-m <num>  The number of minutes to run the stress test.\n");
226     fprintf(stderr, "\t            This option will override the -i option.\n");
227     fprintf(stderr, "\t-n <num>  The number of threads to run.\n");
228     fprintf(stderr, "\t-p <path> UNC path to second directory.\n");
229     fprintf(stderr, "\t-s        Output stats.\n");
230     fprintf(stderr, "\t-t        Do AFS trace logging.\n");
231     fprintf(stderr, "\t-u <UNC>  UNC path to target directory.\n");
232     fprintf(stderr, "\t-v        Turn on verbose mode.\n");
233     fprintf(stderr, "\nNOTE: The switches are not case sensitive.  You\n");
234     fprintf(stderr, "\n      may use either upper or lower case letters.\n\n");
235 }
236
237 void show_results(char *CommandLine, char *TargetDirectory, struct cmd_struct *CommandInfo, 
238                   char *HostName, int NumberOfThreads, int CurrentLoop, int LogID)
239 {
240         struct cmd_struct TotalCommandInfo[CMD_MAX_CMD + 1];
241         int         i;
242     int         j;
243         unsigned    grand_total = 0;
244     char        FileName[256];
245     char        WorkingDirectory[512];
246     struct cmd_struct *FinalCmdInfo;
247
248         for (j = 0; j <= CMD_MAX_CMD; j++) {
249                 TotalCommandInfo[j].count = 0;
250                 TotalCommandInfo[j].min_sec = 0;
251                 TotalCommandInfo[j].max_sec = 0;
252                 TotalCommandInfo[j].MilliSeconds = 0;
253                 TotalCommandInfo[j].total_sec = 0;
254                 TotalCommandInfo[j].total_sum_of_squares = 0;
255                 TotalCommandInfo[j].ErrorCount = 0;
256                 TotalCommandInfo[j].ErrorTime = 0;
257         }
258
259     memset(ExitStatus, '\0', sizeof(ExitStatus[0]) * MAX_HANDLES);
260
261         for (j = 0; j < NumberOfThreads; j++) 
262     { 
263             FinalCmdInfo = CommandInfo + (j * (CMD_MAX_CMD + 1));
264
265                 for (i = 0; i <= CMD_MAX_CMD; i++)
266         {
267                     TotalCommandInfo[i].count += FinalCmdInfo[i].count;
268             TotalCommandInfo[i].total_sec += FinalCmdInfo[i].total_sec; 
269             TotalCommandInfo[i].total_sum_of_squares += FinalCmdInfo[i].total_sum_of_squares; 
270             TotalCommandInfo[i].ErrorCount += FinalCmdInfo[i].ErrorCount; 
271             TotalCommandInfo[i].ErrorTime += FinalCmdInfo[i].ErrorTime; 
272             grand_total += FinalCmdInfo[j].total_sec;
273             if (!TotalCommandInfo[i].min_sec || (TotalCommandInfo[i].min_sec > FinalCmdInfo[i].min_sec))
274                 TotalCommandInfo[i].min_sec = FinalCmdInfo[i].min_sec;
275             if (TotalCommandInfo[i].max_sec < FinalCmdInfo[i].max_sec)
276                 TotalCommandInfo[i].max_sec = FinalCmdInfo[i].max_sec;
277         }
278         }
279
280
281     memset(WorkingDirectory, '\0', sizeof(WorkingDirectory));
282     GetCurrentDirectory(sizeof(WorkingDirectory), WorkingDirectory);
283     sprintf(FileName, "%s\\log%05d\\%s\\ProcessStats.log", WorkingDirectory, LogID, HostName);
284
285     if (PrintStats)
286         LogStats(FileName, 0, CurrentLoop, 1, NumberOfThreads, HostName, -1, TotalCommandInfo, 
287                  CommandLine, TargetDirectory);
288     LogStats(FileName, 1, CurrentLoop, 1, NumberOfThreads, HostName, -1, TotalCommandInfo, 
289              CommandLine, TargetDirectory);
290
291     sprintf(FileName, "%s\\log%05d\\%s", WorkingDirectory, LogID, "MasterStatLog.log");
292     UpdateMasterLog(FileName, TotalCommandInfo);
293     sprintf(FileName, "%s\\log%05d\\%s\\%s", WorkingDirectory, LogID, HostName, "MasterProcessStatLog.log");
294     UpdateMasterLog(FileName, TotalCommandInfo);
295 }
296
297
298 int main(int argc, char *argv[])
299 {
300     int         i;
301     int         LoopCount;
302     int         SecondsToRun;
303     int         NumberOfIterations;
304     int         StressTestUsed = 0;
305     int         rc;
306     int         opt;
307     int         ErrorState;
308     int         NumberOfProcesses;
309     int         NumberOfThreads;
310     int         IterationCount;
311     int         CurrentLoop = 0;
312     int         LogID;
313     time_t      TotalTime;
314     time_t      StartTime;
315     time_t      EndTime;
316     extern char *optarg;
317     extern int  optind;
318     FILE        *Mfp;
319     FILE        *fp;
320     char        *p;
321     char        tbuffer[10];
322     char        buffer[512];
323     char        FileName[256];
324     char        MoveFileName[256];
325     char        Locker[64];
326     char        command[512];
327     char        DateTime[512];
328     char        WorkingDirectory[512];
329     char        CommandLine[512];
330     char        TargetDirectory[512];
331     char        AfsLocker[256];
332     char        HostName[128];
333     char        JobName[128];
334     SYSTEMTIME  SystemTime;
335     SYSTEMTIME  LocalTime;
336     TIME_ZONE_INFORMATION TimeZoneInformation;
337     HANDLE      ExitMutexHandle;
338     HANDLE      JobHandle;
339
340
341     memset(HostName, '\0', sizeof(HostName));
342     memset(PathToSecondDir, '\0', sizeof(PathToSecondDir));
343     memset(Locker, '\0', sizeof(Locker));
344     SecondsToRun = 0;
345     NumberOfIterations = 0;
346     EndOnError = 0;
347     UseLocker = 0;
348     ChronLog = 0;
349     AfsTrace = 0;
350     verbose = 0;
351     NumberOfThreads = 1;
352     NumberOfProcesses = 1;
353     NumberOfThreads = 1;
354     LogID = 0;
355     PrintStats = FALSE;
356
357     while ((opt = getopt(argc, argv, "A:a:BbC:c:D:d:EeF:f:G:g:I:i:L:l:M:m:N:n:P:p:SsTtU:u:Vv")) != EOF)
358     {
359
360         switch (opt)
361         {
362             case 'a':
363             case 'A':
364                 break;
365             case 'b':
366             case 'B':
367                 ChronLog = 1;
368                 break;
369             case 'c':
370             case 'C':
371                 ClientText = optarg;
372                 break;
373             case 'd':
374             case 'D':
375                 StressTestUsed = 1;
376                 NumberOfProcesses = atoi(optarg);
377                 break;
378             case 'e':
379             case 'E':
380                 EndOnError = 1;
381                 break;
382             case 'f':
383             case 'F':
384                 strcpy(HostName, optarg);
385                 for (i = 0; i < (int)strlen(HostName); i++)
386                 {
387                     if ((HostName[i] == '\\') || (HostName[i] == '/'))
388                     {
389                         printf("\nInvalid -F usage...Subdirectories not allowed\n\n");
390                         usage();
391                         exit(1);
392                     }
393                 }
394                 break;
395             case 'g':
396             case 'G':
397                 StressTestUsed = 1;
398                 LogID = atoi(optarg);
399                 break;
400             case 'i':
401             case 'I':
402                 SecondsToRun = 0;
403                 NumberOfIterations = atoi(optarg);
404                 if (NumberOfIterations < 0)
405                     NumberOfIterations = 0;
406                 break;
407 #ifdef HAVE_HESOID
408             case 'l':
409             case 'L':
410                 strcpy(Locker, optarg);
411                 UseLocker = 1;
412                 break;
413 #endif /* HAVE_HESOID */
414             case 'm':
415             case 'M':
416                 NumberOfIterations = 0;
417                 SecondsToRun = atoi(optarg) * 60;
418                 if (SecondsToRun < 0)
419                     SecondsToRun = 0;
420                 break;
421             case 'n':
422             case 'N':
423                 NumberOfThreads = atoi(optarg);
424                 break;
425             case 'p':
426             case 'P':
427                 strcpy(PathToSecondDir, optarg);
428                 for(p = PathToSecondDir; *p; p++)
429                 {
430                     if(*p == '/')
431                         *p = '\\';
432                 }
433                 break;
434             case 's':
435             case 'S':
436                 PrintStats = TRUE;
437                 break;
438             case 't':
439             case 'T':
440                 AfsTrace = 1;
441                 break;
442             case 'u':
443             case 'U':
444                 UseLocker = 0;
445                 strcpy(Locker, optarg);
446                 break;
447             case 'v':
448             case 'V':
449                 verbose = 1;
450                 break;
451             default:
452                 usage();
453                 exit(1);
454                 break;
455         }
456     }
457
458     if (strlen(HostName) == 0)
459     {
460         printf("You must use the -f option to specify a target directory\n\n");
461         usage();
462         exit(1);
463     }
464     if (strlen(Locker) == 0)
465     {
466         printf("You must use either the -u or the -l option\n\n");
467         usage();
468         exit(1);
469     }
470
471     memset(CommandLine, '\0', sizeof(CommandLine));
472     for (i = 1; i < argc; i++)
473     {
474         if (StressTestUsed)
475         {
476             if (!stricmp(argv[i], "-f"))
477             {
478                 char temp[64];
479
480                 strcpy(temp, argv[i + 1]);
481                 temp[strlen(temp) - 5] = '\0';
482                 strcat(CommandLine, argv[i]);
483                 strcat(CommandLine, " ");
484                 strcat(CommandLine, temp);
485                 strcat(CommandLine, " ");
486                 ++i;
487                 continue;
488             }
489         }
490         strcat(CommandLine, argv[i]);
491         strcat(CommandLine, " ");
492     }
493
494     argc -= optind;
495     argv += optind;
496
497     if (strlen(Locker) == 0)
498     {
499         usage();
500         exit(1);
501     }
502
503
504     for(p = Locker; *p; p++)
505     {
506         if(*p == '/')
507             *p = '\\';
508     }
509  
510 #ifdef HAVE_HESOID
511     if (UseLocker)
512     {
513         char *sPtr;
514
515         sprintf(AfsLocker, "\\\\afs\\%s", Locker);
516         memset(buffer, '\0', sizeof(buffer));
517         GetLockerInfo(Locker, buffer);
518         if (strlen(buffer) != 0)
519         {
520             sPtr = strstr(buffer, "/afs/");
521             sPtr += strlen("/afs/");
522             strcpy(TargetDirectory, sPtr);
523             sPtr = strchr(TargetDirectory, ' ');
524             if (sPtr != NULL)
525                 (*sPtr) = '\0';
526             while ((sPtr = strchr(TargetDirectory, '/')) != NULL)
527                 (*sPtr) = '\\';
528         }
529         else
530         {
531             strcpy(TargetDirectory, Locker);
532         }
533     }
534     else
535     {
536 #endif /* HAVE_HESOID */
537         strcpy(AfsLocker, Locker);
538         if (!strnicmp(Locker, "\\\\afs\\", strlen("\\\\afs\\")))
539             strcpy(TargetDirectory, &Locker[strlen("\\\\afs\\")]);
540         else
541             strcpy(TargetDirectory, Locker);
542 #ifdef HAVE_HESOID
543     }
544 #endif /* HAVE_HESOID */
545
546
547     TotalTime = 0;
548     LoopCount = 0;
549     CurrentLoop = 0;
550
551     ExitMutexHandle = CreateMutex(NULL, FALSE, "AfsExitEvent");
552     ChronMutexHandle = CreateMutex(NULL, FALSE, "WinTortureChronMutex");
553     MutexHandle = CreateMutex(NULL, FALSE, "WinTortureMutex");
554     FileMutexHandle = CreateMutex(NULL, FALSE, "WinTortureFileMutex");
555     OSMutexHandle = CreateMutex(NULL, FALSE, "WinTortureOSMutex");
556
557     for (i = 0; i < MAX_THREADS; i++)
558     {
559         ThreadStatus[i] = 2;
560     }
561
562     sprintf(JobName, "%s%05d", "JOB", LogID);
563     JobHandle = CreateJobObject(NULL, JobName);
564     rc = AssignProcessToJobObject(JobHandle, GetCurrentProcess());
565
566     GetCurrentDirectory(sizeof(WorkingDirectory), WorkingDirectory);
567     sprintf(FileName, "%s\\log%05d", WorkingDirectory, LogID);
568     CreateDirectory(FileName, NULL);
569     sprintf(FileName, "%s\\test", WorkingDirectory);
570     CreateDirectory(FileName, NULL);
571     if (!StressTestUsed)
572     {
573         sprintf(FileName, "%s\\log%05d\\Chron.log", WorkingDirectory, LogID);
574         DeleteFile(FileName);
575     }
576
577     sprintf(FileName, "%s\\log%05d\\%s", WorkingDirectory, LogID, HostName);
578     sprintf(command, "rmdir /S /Q %s > %s\\test\\test", FileName, WorkingDirectory);
579     system(command);
580
581     ShutDownEventHandle = CreateEvent(NULL, TRUE, FALSE, "AfsShutdownEvent");
582     PauseEventHandle = CreateEvent(NULL, TRUE, FALSE, "AfsPauseEvent");
583     ContinueEventHandle = CreateEvent(NULL, TRUE, FALSE, "AfsContinueEvent");
584
585     IterationCount = 0;
586     time(&StartTime);
587     if ((NumberOfIterations == 0) && (SecondsToRun == 0))
588         NumberOfIterations = 1;
589     else if (SecondsToRun != 0)
590     {
591         SecondsToRun += StartTime;
592     }
593
594     while (1)
595     {
596         if (SecondsToRun != 0)
597         {
598             time(&StartTime);
599             if (StartTime > (time_t)SecondsToRun)
600             {
601                 break;
602             }
603         }
604         if (NumberOfIterations != 0)
605         {
606             if (LoopCount >= NumberOfIterations)
607             {
608                 break;
609             }
610         }
611         if (rc = WaitForSingleObject(ShutDownEventHandle, 0) == WAIT_OBJECT_0)
612         {
613             break;
614         }
615         ++LoopCount;
616         CurrentLoop = LoopCount;
617
618         _strtime(tbuffer);
619         printf("\nIteration %d started at: %s\n", LoopCount, tbuffer);
620         create_procs(HostName, CommandLine, TargetDirectory, AfsLocker, Locker, 
621                      HostName, NumberOfThreads, CurrentLoop, LogID);
622         _strtime(tbuffer);
623         printf("Iteration %d ended at: %s\n", LoopCount, tbuffer);
624         time(&EndTime);
625         printf("Iteration %d lapse time: %ld seconds\n", LoopCount, EndTime - StartTime);
626         TotalTime += EndTime - StartTime;
627         sprintf(FileName, "%s\\log%05d\\IterationCount", WorkingDirectory, LogID);
628         WaitForSingleObject(MutexHandle, 20 * 1000);
629         if ((fp = fopen(FileName, "r")) != NULL)
630         {
631             fgets(buffer, sizeof(buffer), fp);
632             IterationCount = atoi(buffer);
633             fclose(fp);
634         }
635         ++IterationCount;
636         fp = fopen(FileName, "w");
637         fprintf(fp, "%d\n", IterationCount);
638         fclose(fp);
639         ReleaseMutex(MutexHandle);
640         if (EndOnError)
641         {
642             for (i = 0; i < MAX_THREADS; i++)
643             {
644                 if (ThreadStatus[i] == 1)
645                 {
646                     break;
647                 }
648             }
649             if (i >= MAX_THREADS)
650                 break;
651         }
652         ErrorState = 0;
653         for (i = 0; i < MAX_THREADS; i++)
654         {
655             if (ThreadStatus[i] == 0)
656             {
657                 ErrorState = 1;
658                 ThreadStatus[i] = 1;
659             }
660         }
661         if (ErrorState)
662         {
663             printf("\nSleeping for 3 minutes for error recovery\n\n");
664             Sleep(3 * 60 * 1000);
665         }
666     }
667     if (LoopCount == 0)
668         return(0);
669
670     sprintf(FileName, ".\\log%05d\\%s\\Master.log", LogID, HostName);
671     Mfp = fopen(FileName, "w+");
672     fprintf(Mfp, "Average Iteration Time = %.02f minutes\n\n", ((float)TotalTime/(float)(LoopCount))/60.0);
673     for (i = 0; i < NumberOfThreads; i++)
674     {
675         sprintf(FileName, ".\\log%05d\\%s\\Thread_%05d.log", LogID, HostName, i);
676         fp = fopen(FileName, "r");
677         if (fp != NULL)
678         {
679             fprintf(Mfp, "START OF THREAD %d\n\n", i);
680             while (fgets(buffer, 512, fp) != NULL)
681             {
682                 fprintf(Mfp, "%s", buffer);
683             }
684             fclose(fp);
685             fprintf(Mfp, "END OF THREAD %d\n\n", i);
686         }
687     }
688     fclose(Mfp);
689
690     memset(WorkingDirectory, '\0', sizeof(WorkingDirectory));
691     GetCurrentDirectory(sizeof(WorkingDirectory), WorkingDirectory);
692
693     sprintf(FileName, "%s\\log%05d\\%s\\%s", WorkingDirectory, LogID, HostName, "MasterProcessStatLog.log");
694     sprintf(MoveFileName, "%s\\log%05d\\%s\\%s", WorkingDirectory, LogID, HostName, "MasterProcessStatLogRaw.log");
695     BuildMasterStatLog(FileName, MoveFileName, NumberOfProcesses, NumberOfThreads, CommandLine, LoopCount, 
696                        TargetDirectory, -1);
697
698 //    sprintf(DateTime, "%s-%04d%02d%02d-%02d%02d%02d", HostName,
699 //                                                      LocalTime.wYear, 
700 //                                                      LocalTime.wMonth, 
701 //                                                      LocalTime.wDay,
702 //                                                      LocalTime.wHour,
703 //                                                      LocalTime.wMinute,
704 //                                                      LocalTime.wSecond);
705 //    sprintf(command, "rename %s\\log%05d\\%s %s", WorkingDirectory, LogID, HostName, DateTime);
706 //    rc = system(command);
707
708     WaitForSingleObject(ExitMutexHandle, 20 * 1000);
709     Sleep(3 * 1000);
710
711     GetSystemTime(&SystemTime);
712     GetTimeZoneInformation(&TimeZoneInformation);
713     SystemTimeToTzSpecificLocalTime(&TimeZoneInformation, &SystemTime, &LocalTime);
714
715     NumberOfProcesses = 0;
716     sprintf(FileName, "%s\\log%05d\\ProcessCount", WorkingDirectory, LogID);
717     if ((fp = fopen(FileName, "r")) != NULL)
718     {
719         fgets(buffer, sizeof(buffer), fp);
720         NumberOfProcesses = atoi(buffer);
721         fclose(fp);
722     }
723     ++NumberOfProcesses;
724     fp = fopen(FileName, "w");
725     fprintf(fp, "%d\n", NumberOfProcesses);
726     fclose(fp);
727
728     if (FindProcessCount("wintorture.exe", JobHandle) == 1)
729     {
730         NumberOfProcesses = 0;
731         sprintf(FileName, "%s\\log%05d\\ProcessCount", WorkingDirectory, LogID);
732         sprintf(MoveFileName, "%s\\log%05d\\ProcessCountRaw", WorkingDirectory, LogID);
733         if ((fp = fopen(FileName, "r")) != NULL)
734         {
735             fgets(buffer, sizeof(buffer), fp);
736             NumberOfProcesses = atoi(buffer);
737             fclose(fp);
738             MoveFile(FileName, MoveFileName);
739         }
740
741         IterationCount = 0;
742         sprintf(FileName, "%s\\log%05d\\IterationCount", WorkingDirectory, LogID);
743         sprintf(MoveFileName, "%s\\log%05d\\IterationCountRaw", WorkingDirectory, LogID);
744         if ((fp = fopen(FileName, "r")) != NULL)
745         {
746             fgets(buffer, sizeof(buffer), fp);
747             IterationCount = atoi(buffer);
748             fclose(fp);
749             MoveFile(FileName, MoveFileName);
750         }
751
752         sprintf(FileName, "%s\\log%05d\\%s", WorkingDirectory, LogID, "MasterStatLog.log");
753         sprintf(MoveFileName, "%s\\log%05d\\%s", WorkingDirectory, LogID, "MasterStatLogRaw.log");
754         BuildMasterStatLog(FileName, MoveFileName, NumberOfProcesses, NumberOfThreads, 
755                            CommandLine, IterationCount, TargetDirectory, -2);
756         sprintf(DateTime, "%s%05d-%04d%02d%02d-%02d%02d%02d", "log",
757                                                           LogID,
758                                                           LocalTime.wYear, 
759                                                           LocalTime.wMonth, 
760                                                           LocalTime.wDay,
761                                                           LocalTime.wHour,
762                                                           LocalTime.wMinute,
763                                                           LocalTime.wSecond);
764         sprintf(command, "rename %s\\log%05d %s", WorkingDirectory, LogID, DateTime);
765         rc = system(command);
766         ResetEvent(ShutDownEventHandle);
767         ResetEvent(PauseEventHandle);
768         ResetEvent(ContinueEventHandle);
769         CloseHandle(ShutDownEventHandle);
770         CloseHandle(PauseEventHandle);
771         CloseHandle(ContinueEventHandle);
772
773     }
774
775     ReleaseMutex(ExitMutexHandle);
776     CloseHandle(JobHandle);
777     return 0;
778 }
779
780 int ProcessNameAndID(DWORD processID, char *ProcessName, HANDLE JobHandle)
781 {
782     char    szProcessName[1024] = "unknown";
783     char    FileName[1024];
784     char    WorkingDirectory[512];
785     HANDLE  hProcess;
786     int     Count;
787
788     memset(WorkingDirectory, '\0', sizeof(WorkingDirectory));
789     GetCurrentDirectory(sizeof(WorkingDirectory), WorkingDirectory);
790     strcat(WorkingDirectory, "\\");
791     Count = 0;
792     hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
793     if (hProcess)
794     {
795         HMODULE hMod;
796         DWORD cbNeeded;
797
798         if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
799         {
800             memset(szProcessName, '\0', sizeof(szProcessName));
801             GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName));
802             if (!stricmp(szProcessName, ProcessName))
803             {
804                 memset(FileName, '\0', sizeof(FileName));
805                 if (GetModuleFileNameEx(hProcess, hMod, FileName, sizeof(FileName) - 1))
806                 {
807                     if (!strnicmp(WorkingDirectory, FileName, strlen(WorkingDirectory)))
808                     {
809                         ++Count;
810                     }
811                 }
812             }
813         }
814     }
815     CloseHandle(hProcess);
816     return(Count);
817 }
818
819 DWORD FindProcessCount(char *ProcessName, HANDLE JobHandle)
820 {
821     DWORD       aProcesses[8092];
822     DWORD       cbNeeded;
823     DWORD       cProcesses;
824     int         Count;
825     int         rc;
826     unsigned    int i;
827     JOBOBJECT_BASIC_PROCESS_ID_LIST IdList;
828
829     rc = QueryInformationJobObject(JobHandle, JobObjectBasicProcessIdList, &IdList, sizeof(IdList), NULL);
830     return(IdList.NumberOfAssignedProcesses);
831
832     if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
833         return(1);
834
835     Count = 0;
836     cProcesses = cbNeeded / sizeof(DWORD);
837
838     for (i = 0; i < cProcesses; i++)
839     {
840
841 //        Count += ProcessNameAndID(aProcesses[i], ProcessName, JobHandle);
842     }
843
844     return(Count);
845 }
846
847 char *_progname(char *nargv0)
848 {
849     char    *tmp;
850
851     tmp = strrchr(nargv0, '/');
852     if (tmp)
853         tmp++;
854     else
855         tmp = nargv0;
856     return(tmp);
857 }
858
859 #define BADCH   (int)'?'
860 #define BADARG  (int)':'
861 #define EMSG    ""
862
863 int getopt(int nargc, char *nargv[], char *ostr)
864 {
865     static char *__progname = 0;
866     static char *place = EMSG;          /* option letter processing */
867     char *oli;                          /* option letter list index */
868
869     __progname = __progname?__progname:_progname(*nargv);
870
871     if (optreset || !*place)
872     {
873         optreset = 0;
874         if (optind >= nargc || *(place = nargv[optind]) != '-')
875         {
876             place = EMSG;
877             return (-1);
878         }
879         if (place[1] && *++place == '-' && place[1] == '\0')
880         {
881             ++optind;
882             place = EMSG;
883             return (-1);
884         }
885     }
886     if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) 
887     {
888         if (optopt == (int)'-')
889             return (-1);
890         if (!*place)
891             ++optind;
892         if (opterr && *ostr != ':')
893             (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname, optopt);
894         return (BADCH);
895     }
896     if (*++oli != ':') 
897     {
898         optarg = NULL;
899         if (!*place)
900             ++optind;
901     }
902     else
903     {
904         if (*place)
905             optarg = place;
906         else if (nargc <= ++optind) 
907         {
908             place = EMSG;
909             if (*ostr == ':')
910                 return (BADARG);
911             if (opterr)
912                 (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname, optopt);
913             return (BADCH);
914         }
915         else
916             optarg = nargv[optind];
917         place = EMSG;
918         ++optind;
919     }
920     return (optopt);
921 }