--- joko/Uni/BSArch/04/bmp_fractal.c 2006/07/02 01:51:26 1.10 +++ joko/Uni/BSArch/04/bmp_fractal.c 2006/07/02 12:21:01 1.16 @@ -5,7 +5,7 @@ * Uebung 4.4 */ -// $Id: bmp_fractal.c,v 1.10 2006/07/02 01:51:26 joko Exp $ +// $Id: bmp_fractal.c,v 1.16 2006/07/02 12:21:01 joko Exp $ #include #include @@ -15,9 +15,7 @@ #define YSIZE 500 #include "algorithm.h" -#define MASTER -1 - -BOOL VERBOSE = TRUE; +BOOL VERBOSE = FALSE; /* BMP Header */ @@ -51,12 +49,12 @@ 0, NULL )) { - fprintf(stderr,"%s : %s\n",msg,lpMsgBuf); + fprintf(stderr, "%s: %s\n", msg, lpMsgBuf); LocalFree(lpMsgBuf); } else { - fprintf(stderr,"Error at FormatMesage: %d\n",err=GetLastError()); + fprintf(stderr, "Error at FormatMesage: %d\n",err=GetLastError()); } exit(err); } @@ -70,7 +68,7 @@ // open file handle fd = fopen(filename, "wb+"); if (NULL == fd) { - perror("open"); + perror("Error while opening file for writing"); exit(1); } @@ -79,7 +77,7 @@ // error checking if (-1 == len || len != sizeof(header)) { - perror("write"); + perror("Error while writing header to file"); exit(2); } @@ -88,7 +86,7 @@ for (i = 0; i < img_size; i++) { len = fwrite("\0\0\0", 1, 3, fd); if (-1 == len || len != 3) { - perror("write"); + perror("Error while writing data to file"); exit(4); } } @@ -127,16 +125,16 @@ // debugging if (VERBOSE) { - printf("----------------------------------------------\n"); - printf("thread_id: %i\n", thread_id); - printf("arg.start_row: %i\n", args->start_row); - printf("arg.number_of_rows: %i\n", args->number_of_rows); - printf("segment_start: %p\n", pDataBitmapSegment); + fprintf(stdout, "----------------------------------------------\n"); + fprintf(stdout, "thread_id: %i\n", thread_id); + fprintf(stdout, "arg.start_row: %i\n", args->start_row); + fprintf(stdout, "arg.number_of_rows: %i\n", args->number_of_rows); + fprintf(stdout, "segment_start: %p\n", pDataBitmapSegment); } // calculate fractal for (y = (args->start_row + args->number_of_rows) - 1; y >= args->start_row; y--) { - //printf("calc: thread=%i; y=%i limits: %i,%i p: %p\n", thread_id, y, args->start_row, args->number_of_rows, pDataBitmapSegment); + //fprintf(stdout, "calc: thread=%i; y=%i limits: %i,%i p: %p\n", thread_id, y, args->start_row, args->number_of_rows, pDataBitmapSegment); for (x = 0; x < XSIZE; x++) { getColorValuesAt(x * (2.0 / XSIZE) - 1.5, y * (2.0 / YSIZE) - 1.0, &bgr[2], &bgr[1], &bgr[0]); @@ -153,11 +151,31 @@ } if (VERBOSE) - printf("thread finished: %i\n", thread_id); + fprintf(stdout, "thread finished: %i\n", thread_id); return 0; } +BOOL scan_argv(int argc, char *argv[], char opt_name[], char *opt_value) { + int i; + char * opt_current_name; + char * opt_current_value; + + //printf("searching for: '%s'\n", opt_name); + + for (i = 1; i < argc; i++) { + opt_current_name = argv[i]; + if (strcmp(opt_current_name, opt_name) == 0) { + opt_current_value = argv[i+1]; + if (opt_current_value != NULL) { + strcpy(opt_value, opt_current_value); + } + return TRUE; + } + } + return FALSE; +} + int main(int argc, char *argv[]) { @@ -168,50 +186,99 @@ unsigned char *pDataBitmap; // workers - int workers = 5; + int workers; int worker_index, worker_rows, worker_startrow; HANDLE *worker_handles; PWORKERARGS worker_args; + int worker_count; // threads or processes? - BOOL use_processes = TRUE; - int worker_id = MASTER; + BOOL use_processes = FALSE; + BOOL is_worker_process = FALSE; // information for creating processes STARTUPINFO si; PROCESS_INFORMATION pi; - char szCmdline[1024]; + char szCmdline[65536]; + // command line stuff + char arg_option[1024]; + char arg_value[1024]; + char *bmp_filename; + char *verbose_option = ""; - // "parse" command line arguments - if (argc >= 2) { - worker_id = atoi(argv[1]); + + // parse command line arguments + if (argc < 2) { + fprintf(stderr, "Can not run without arguments!\nPlease specify '-t {number of threads}' or '-p {number of processes}' and an image filename.\n"); + exit(EXIT_FAILURE); } - if (VERBOSE) { - printf("==============================================================\n"); - printf("worker-id: %i\n", worker_id); + if (scan_argv(argc, argv, "--verbose", arg_value)) { + VERBOSE = TRUE; } - // create empty bmp-file (black background) - if (worker_id == MASTER) - write_blank_file("test.bmp"); + if (scan_argv(argc, argv, "--worker", arg_value)) { + use_processes = TRUE; + is_worker_process = TRUE; + + } else if (scan_argv(argc, argv, "-p", arg_value)) { + if (strlen(arg_value) == 0) { + fprintf(stderr, "Please specify number of processes!\n"); + exit(EXIT_FAILURE); + } + use_processes = TRUE; + is_worker_process = FALSE; + workers = atoi(arg_value); + + } else if (scan_argv(argc, argv, "-t", arg_value)) { + if (strlen(arg_value) == 0) { + fprintf(stderr, "Please specify number of threads!\n"); + exit(EXIT_FAILURE); + } + use_processes = FALSE; + is_worker_process = FALSE; + workers = atoi(arg_value); + + } + + + if (VERBOSE && use_processes) { + fprintf(stdout, "===================================================== "); + if (is_worker_process) + fprintf(stdout, "WORKER-PROCESS\n"); + else + fprintf(stdout, "MASTER-PROCESS\n"); + } - if (worker_id == MASTER) { + + // master creates memory mapped file ("empty" image) + if (!is_worker_process) { + + if (argc < 4) { + fprintf(stderr, "Must give filename of image as third argument!\n"); + exit(EXIT_FAILURE); + } + + bmp_filename = argv[3]; - /* open file for reading and writing */ - hFile = CreateFile("test.bmp", GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + // create empty bmp-file (black background) + write_blank_file(bmp_filename); + + // open file for reading and writing + hFile = CreateFile(bmp_filename, GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { err = GetLastError(); printErrorAndExit("Error at CreateFile",err); } - /* create the file mapping object */ + // create the file mapping object hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, "bmp_fractal"); if (NULL == hMap) { printErrorAndExit("Error at CreateFileMapping", GetLastError()); } - + + // worker uses existing memory mapped file } else { // open existing mapping object @@ -220,7 +287,7 @@ printErrorAndExit("Error at OpenFileMapping", GetLastError()); } - /* map the whole file into the process context */ + // map the whole file into the process context pData = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); if (NULL == pData) { printErrorAndExit("Error at MapViewOfFile", GetLastError()); @@ -232,24 +299,23 @@ // debugging if (VERBOSE) { - printf("pos. of file: %p\n", pData); - printf("pos. of bitmap: %p\n", pDataBitmap); + fprintf(stdout, "pos. of file: %p\n", pData); + fprintf(stdout, "pos. of bitmap: %p\n", pDataBitmap); } - if (use_processes && worker_id != MASTER) { + if (use_processes && is_worker_process) { if (VERBOSE) - printf("inside worker-process\n"); - - worker_index = worker_id; + fprintf(stdout, "inside worker-process\n"); + // get segment information from command line worker_startrow = atoi(argv[2]); worker_rows = atoi(argv[3]); // allocate memory for one worker's arguments if ((worker_args = malloc(sizeof(worker_args[0]))) == NULL) - perror("malloc"), exit(1); + perror("Error while allocating memory for worker arguments via malloc"), exit(1); // assign worker's arguments worker_args[0].start_row = worker_startrow; @@ -257,8 +323,12 @@ worker_args[0].pBitmap = pDataBitmap; fractal_create_segment(&worker_args[0]); + + // cleanup mmap-handle + if (!CloseHandle(hMap)) + printErrorAndExit("Error at CloseHandle", GetLastError()); - return 0; + return 0; } /* @@ -278,17 +348,17 @@ // allocate memory for table of all worker handles if ((worker_handles = malloc(workers * sizeof(worker_handles[0]))) == NULL) - perror("malloc"), exit(1); + perror("Error while allocating memory for worker handles via malloc"), exit(1); // allocate memory for table of all worker arguments if ((worker_args = malloc(workers * sizeof(worker_args[0]))) == NULL) - perror("malloc"), exit(1); + perror("Error while allocating memory for worker arguments via malloc"), exit(1); // calculate bitmap segment length for workers worker_rows = YSIZE / workers; if (VERBOSE) - printf("rows for each worker: %i\n", worker_rows); + fprintf(stdout, "rows for each worker: %i\n", worker_rows); // start workers for (worker_index = 0; worker_index < workers; worker_index++) { @@ -304,7 +374,7 @@ if (worker_index == workers - 1) { worker_rows = YSIZE - worker_startrow; if (VERBOSE) - printf("rows for last worker: %i\n", worker_rows); + fprintf(stdout, "rows for last worker: %i\n", worker_rows); } // assign each worker's arguments @@ -328,7 +398,11 @@ } else { - _snprintf(szCmdline, 1023, "%s %i %i %i", argv[0], worker_index + 1, worker_startrow, worker_rows); + if (VERBOSE) + verbose_option = "--verbose"; + _snprintf(szCmdline, 1023, "%s %s %i %i %s", argv[0], "--worker", worker_startrow, worker_rows, verbose_option); + if (VERBOSE) + fprintf(stdout, "starting worker process: %s\n", szCmdline); ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); @@ -353,11 +427,15 @@ } - // wait for all threads if (VERBOSE) - printf("waiting for workers to finish...\n"); - if (WaitForMultipleObjects(workers, worker_handles, TRUE, INFINITE) == WAIT_FAILED) - perror("WaitForMultipleObjects"); + fprintf(stdout, "waiting for workers to finish...\n"); + + // wait for all workers + for (worker_index = 0; worker_index < workers; worker_index += MAXIMUM_WAIT_OBJECTS) { + worker_count = ((workers - worker_index) > MAXIMUM_WAIT_OBJECTS) ? MAXIMUM_WAIT_OBJECTS : (workers - worker_index); + if (WaitForMultipleObjects(worker_count, &worker_handles[worker_index], TRUE, INFINITE) == WAIT_FAILED) + printErrorAndExit("Error at WaitForMultipleObjects", GetLastError()); + } // debugging: just run single thread //if (WaitForSingleObject(worker_handles[0], INFINITE) == WAIT_FAILED) @@ -367,20 +445,20 @@ for (worker_index = 0; worker_index < workers; worker_index++) CloseHandle(worker_handles[worker_index]); - /* write the result into the file */ + // write the result into the file if (!FlushViewOfFile(pData, 0)) { err = GetLastError(); printErrorAndExit("Error at UnmapViewOfFile", err); } - /* remove the mapped file */ + // remove the mapped file if (!UnmapViewOfFile(pData)) { err = GetLastError(); printErrorAndExit("Error at UnmapViewOfFile", err); exit(err); } - /* cleanup handles */ + // cleanup handles if (!CloseHandle(hMap) || !CloseHandle(hFile) ) { err = GetLastError(); printErrorAndExit("Error at CloseHandle", err);