Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

688 lines
16 KiB

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "windows.h"
HANDLE PrintfAvailable;
HANDLE ReadyToWork;
HANDLE ReadyToReport;
HANDLE DoneReporting;
HANDLE StartOperationsEvent;
HANDLE BeginReporting;
typedef struct _THREAD_WORK {
char *NameOfPort;
HANDLE FileToUse;
DWORD NumberOfChars;
BOOL DoWrite;
OVERLAPPED Ol;
UCHAR BufferForOp[1];
} THREAD_WORK,*PTHREAD_WORK;
char NameOfWrite[] = "Write";
char NameOfRead[] = "Read";
DWORD
WorkThread(
LPVOID ThreadContext
)
{
PTHREAD_WORK ToDo = ThreadContext;
DWORD FinalCountOfOp;
DWORD LastError;
clock_t Start;
clock_t Finish;
BOOL OpDone;
char *OperationName;
OperationName = (ToDo->DoWrite)?(&NameOfWrite[0]):(&NameOfRead[0]);
if (!ReleaseSemaphore(ReadyToWork,1,NULL)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't release the ready to start semaphore for port %s\n",
ToDo->NameOfPort
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
ReleaseSemaphore(ReadyToReport,1,NULL);
ReleaseSemaphore(DoneReporting,1,NULL);
return 1;
}
WaitForSingleObject(StartOperationsEvent,-1);
if (ToDo->DoWrite) {
Start = clock();
OpDone = WriteFile(
ToDo->FileToUse,
&ToDo->BufferForOp[0],
ToDo->NumberOfChars,
&FinalCountOfOp,
&ToDo->Ol
);
} else {
Start = clock();
OpDone = ReadFile(
ToDo->FileToUse,
&ToDo->BufferForOp[0],
ToDo->NumberOfChars,
&FinalCountOfOp,
&ToDo->Ol
);
}
if (!OpDone) {
LastError = GetLastError();
if (LastError != ERROR_IO_PENDING) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Could not start the %s for %s - error: %d\n",
OperationName,
ToDo->NameOfPort,
LastError
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
ReleaseSemaphore(ReadyToReport,1,NULL);
ReleaseSemaphore(DoneReporting,1,NULL);
return 1;
}
if (!GetOverlappedResult(
ToDo->FileToUse,
&ToDo->Ol,
&FinalCountOfOp,
TRUE
)) {
LastError = GetLastError();
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Wait on %s for port %s failed - error: %d\n",
OperationName,
ToDo->NameOfPort,
LastError
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
ReleaseSemaphore(ReadyToReport,1,NULL);
ReleaseSemaphore(DoneReporting,1,NULL);
return 1;
}
}
Finish = clock();
if (!ReleaseSemaphore(ReadyToReport,1,NULL)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't release the ready to report semaphore for port %s\n",
ToDo->NameOfPort
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
return 1;
}
WaitForSingleObject(BeginReporting,-1);
WaitForSingleObject(PrintfAvailable,-1);
printf("%s for %s\n",OperationName,ToDo->NameOfPort);
printf("-------Time to write %f\n",(((double)(Finish-Start))/CLOCKS_PER_SEC));
printf("-------Chars per second %f\n",((double)FinalCountOfOp)/(((double)(Finish-Start))/CLOCKS_PER_SEC));
printf("-------Number actually done by %s: %d.\n",OperationName,FinalCountOfOp);
//
// if this is the write code then check the data.
//
if (ToDo->DoWrite) {
DWORD TotalCount;
DWORD j;
for (
TotalCount = 0;
TotalCount < FinalCountOfOp;
) {
for (
j = (0xff - 10);
j != 0; // When it wraps around.
j++
) {
if (ToDo->BufferForOp[TotalCount] != ((UCHAR)j)) {
WaitForSingleObject(PrintfAvailable,-1);
printf("Bad data starting at: %d\n",TotalCount);
printf("BufferForOp[TotalCount]: %x\n",ToDo->BufferForOp[TotalCount]);
printf("j: %x\n",j);
ReleaseSemaphore(PrintfAvailable,1,NULL);
goto DoneWithCheck;
}
TotalCount++;
if (TotalCount >= FinalCountOfOp) {
goto DoneWithCheck;
}
}
}
DoneWithCheck:;
}
ReleaseSemaphore(PrintfAvailable,1,NULL);
if (!ReleaseSemaphore(DoneReporting,1,NULL)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't release the done reporting semaphore for port %s\n",
ToDo->NameOfPort
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
}
return 1;
}
void main(int argc,char *argv[]) {
HANDLE hFile;
DCB MyDcb;
DWORD NumberOfChars;
DWORD UseBaud;
DWORD NumberOfDataBits = 8;
COMMTIMEOUTS To;
DWORD i;
DWORD NumberOfPorts;
if (argc < 4) {
printf("Ivalid number of args - tserialm #chars Baud COMx [COMX...]\n");
}
NumberOfPorts = argc - 3;
sscanf(argv[1],"%d",&NumberOfChars);
sscanf(argv[2],"%d",&UseBaud);
//
// Create a global event that each thread will wait on
// to start it's work.
//
StartOperationsEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
);
if (!StartOperationsEvent) {
printf("StartOperationsEvent could not be created\n");
exit(1);
}
//
// Create a global event that each thread will wait on
// to start reporting its results.
//
BeginReporting = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
);
if (!BeginReporting) {
printf("Begin reporting could not be created\n");
exit(1);
}
//
// Create a semaphore that is used to make sure that
// only one thread is doing printf at a time.
//
PrintfAvailable = CreateSemaphore(
NULL,
1,
1,
NULL
);
if (!PrintfAvailable) {
printf("PrintfAvailable could not be created\n");
exit(1);
}
//
// Create a semaphore that is used to indicate that all threads
// are waiting to work.
//
ReadyToWork = CreateSemaphore(
NULL,
0,
NumberOfPorts*2,
NULL
);
if (!ReadyToWork) {
printf("Ready to work could not be created\n");
exit(1);
}
//
// Create a semaphore that is used to indicate that all threads
// are ready to report their results.
//
ReadyToReport = CreateSemaphore(
NULL,
0,
NumberOfPorts*2,
NULL
);
if (!ReadyToReport) {
printf("Ready to report could not be created\n");
exit(1);
}
//
// Create a semaphore that is used to indicate that all threads
// are done reporting.
//
DoneReporting = CreateSemaphore(
NULL,
0,
NumberOfPorts*2,
NULL
);
if (!DoneReporting) {
printf("Done reporting could not be created\n");
exit(1);
}
for (
i = 1;
i <= NumberOfPorts;
i++
) {
PTHREAD_WORK ReadContext;
PTHREAD_WORK WriteContext;
DWORD TotalCount;
DWORD j;
DWORD ThreadId;
if ((hFile = CreateFile(
argv[i+2],
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL
)) == ((HANDLE)-1)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't open %s\n",
argv[i+2]
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
To.ReadIntervalTimeout = 0;
To.ReadTotalTimeoutMultiplier = ((1000+(((UseBaud+9)/10)-1))/((UseBaud+9)/10));
if (!To.ReadTotalTimeoutMultiplier) {
To.ReadTotalTimeoutMultiplier = 1;
}
To.WriteTotalTimeoutMultiplier = ((1000+(((UseBaud+9)/10)-1))/((UseBaud+9)/10));
if (!To.WriteTotalTimeoutMultiplier) {
To.WriteTotalTimeoutMultiplier = 1;
}
To.ReadTotalTimeoutConstant = 5000;
To.WriteTotalTimeoutConstant = 5000;
if (!SetCommTimeouts(
hFile,
&To
)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't set the timeouts for port %s error %d\n",
argv[i+2],
GetLastError()
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
if (!GetCommState(
hFile,
&MyDcb
)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't get the comm state for port %s error %d\n",
argv[i+2],
GetLastError()
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
MyDcb.BaudRate = UseBaud;
MyDcb.ByteSize = 8;
MyDcb.Parity = NOPARITY;
MyDcb.StopBits = ONESTOPBIT;
MyDcb.fOutxDsrFlow = TRUE;
MyDcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
if (!SetCommState(
hFile,
&MyDcb
)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't set the comm state for port %s error %d\n",
argv[i+2],
GetLastError()
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
//
// Alloc two thread contexts for the read and the
// write thread.
//
ReadContext = malloc(sizeof(THREAD_WORK)+(NumberOfChars-1));
if (!ReadContext) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't create the read thread context for %s\n",
argv[i+2]
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
WriteContext = malloc(sizeof(THREAD_WORK)+(NumberOfChars-1));
if (!WriteContext) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't create the write thread context for %s\n",
argv[i+2]
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
ReadContext->NameOfPort = argv[i+2];
ReadContext->FileToUse = hFile;
ReadContext->NumberOfChars = NumberOfChars;
ReadContext->DoWrite = FALSE;
if (!(ReadContext->Ol.hEvent = CreateEvent(
NULL,
FALSE,
FALSE,
NULL
))) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't create read overlapped event for %s\n",
argv[i+2]
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
} else {
ReadContext->Ol.Internal = 0;
ReadContext->Ol.InternalHigh = 0;
ReadContext->Ol.Offset = 0;
ReadContext->Ol.OffsetHigh = 0;
}
WriteContext->NameOfPort = argv[i+2];
WriteContext->FileToUse = hFile;
WriteContext->NumberOfChars = NumberOfChars;
WriteContext->DoWrite = TRUE;
if (!(WriteContext->Ol.hEvent = CreateEvent(
NULL,
FALSE,
FALSE,
NULL
))) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't create write overlapped event for %s\n",
argv[i+2]
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
} else {
WriteContext->Ol.Internal = 0;
WriteContext->Ol.InternalHigh = 0;
WriteContext->Ol.Offset = 0;
WriteContext->Ol.OffsetHigh = 0;
}
for (
TotalCount = 0;
TotalCount < NumberOfChars;
) {
for (
j = (0xff - 10);
j != 0; // When it wraps around
j++
) {
WriteContext->BufferForOp[TotalCount] = (UCHAR)j;
TotalCount++;
if (TotalCount >= NumberOfChars) {
break;
}
}
}
if (!CreateThread(
NULL,
0,
WorkThread,
ReadContext,
0,
&ThreadId
)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't create the read thread for %s\n",
argv[i+2]
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
if (!CreateThread(
NULL,
0,
WorkThread,
WriteContext,
0,
&ThreadId
)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Couldn't create the write thread for %s\n",
argv[i+2]
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
}
//
// Wait for all the threads to signal that they
// are ready to work
//
for (
i = 0;
i < NumberOfPorts*2;
i++
) {
if (WaitForSingleObject(ReadyToWork,-1)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Got an error waiting for threads to be ready to work: %d\n",i
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
}
//
// Tell them to start working.
//
SetEvent(StartOperationsEvent);
//
// Wait for all the threads to report that they
// are done with their io an that they are ready to report.
//
for (
i = 0;
i < NumberOfPorts*2;
i++
) {
if (WaitForSingleObject(ReadyToReport,-1)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Got an error waiting for threads to be ready to report.\n"
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
}
//
// Tell all the threads that its ok for them to report.
//
SetEvent(BeginReporting);
//
// Wait for all the thread to complete reporting. Then
// we can finish.
//
for (
i = 0;
i < NumberOfPorts*2;
i++
) {
if (WaitForSingleObject(DoneReporting,-1)) {
WaitForSingleObject(PrintfAvailable,-1);
printf(
"Got an error waiting for threads to be done reporting.\n"
);
ReleaseSemaphore(PrintfAvailable,1,NULL);
exit(1);
}
}
//
// All gone.
//
exit(1);
}