|
|
#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); }
|