--- joko/Uni/BSArch/04/bmp_fractal.c 2006/07/01 11:45:35 1.3 +++ joko/Uni/BSArch/04/bmp_fractal.c 2006/07/02 12:41:56 1.18 @@ -5,7 +5,7 @@ * Uebung 4.4 */ -// $Id: bmp_fractal.c,v 1.3 2006/07/01 11:45:35 joko Exp $ +// $Id: bmp_fractal.c,v 1.18 2006/07/02 12:41:56 joko Exp $ #include #include @@ -15,6 +15,11 @@ #define YSIZE 500 #include "algorithm.h" +#define MAX_COMMAND_LINE 65536 +#define MMAP_NAME "bmp_fractal" + +BOOL VERBOSE = FALSE; + /* BMP Header */ unsigned char header[54]={0x42,0x4d, // signature BM @@ -47,12 +52,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); } @@ -66,7 +71,7 @@ // open file handle fd = fopen(filename, "wb+"); if (NULL == fd) { - perror("open"); + perror("Error while opening file for writing"); exit(1); } @@ -75,7 +80,7 @@ // error checking if (-1 == len || len != sizeof(header)) { - perror("write"); + perror("Error while writing header to file"); exit(2); } @@ -84,49 +89,218 @@ 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); } } // close file handle - fclose(fd); + if (fclose(fd) != 0) { + perror("Error while closing file handle"); + exit(1); + } } -int main(int argc, char *argv[]) { - int len,x,y; +// arguments for each thread +typedef struct _WorkerArguments { + int start_row; + int number_of_rows; + unsigned char * pBitmap; +} WORKERARGS, *PWORKERARGS; + +// worker thread - main entry function +DWORD WINAPI fractal_create_segment (LPVOID lpParam) { + + // thread stuff + int thread_id; + PWORKERARGS args; + unsigned char *pDataBitmapSegment; + + // fractal calculation + int x, y; char bgr[3]; - short svalue; - int lvalue; - HANDLE hMap, hFile; - DWORD err, size; - int elems; + // get worker arguments + args = (PWORKERARGS)lpParam; + + // calculate pointer to beginning of segment + pDataBitmapSegment = (unsigned char *)((INT_PTR)args->pBitmap + (YSIZE - (args->start_row + args->number_of_rows)) * 3 * XSIZE); + + // debugging + if (VERBOSE) { + thread_id = GetCurrentThreadId(); + 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--) { + //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++) { + + // call to function in static linked library + getColorValuesAt(x * (2.0 / XSIZE) - 1.5, y * (2.0 / YSIZE) - 1.0, &bgr[2], &bgr[1], &bgr[0]); + + // transfer color values to current pixel + pDataBitmapSegment[0] = bgr[0]; + pDataBitmapSegment[1] = bgr[1]; + pDataBitmapSegment[2] = bgr[2]; + + // move pointer to next pixel + pDataBitmapSegment += 3; + + } + //no padding required because 1500%4 =0 ??? + } + + if (VERBOSE) + 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[]) { + + // MMF support + DWORD err; + HANDLE hMap, hFile; LPVOID pData; - unsigned char *pDataBitmap, *pDataBitmapCurrent; + unsigned char *pDataBitmap; + + // workers + int workers; + int worker_index, worker_rows, worker_startrow; + HANDLE *worker_handles; + PWORKERARGS worker_args; + int worker_count; + + // threads or processes? + BOOL use_processes = FALSE; + BOOL is_worker_process = FALSE; - int offset; + // information for creating processes + STARTUPINFO si; + PROCESS_INFORMATION pi; + char szCmdline[MAX_COMMAND_LINE]; - // create empty file (black background) - write_blank_file("test.bmp"); + // command line stuff + char arg_option[1024]; + char arg_value[1024]; + char *bmp_filename; + char *verbose_option = ""; - /* open file for reading and writing */ - hFile = CreateFile("test.bmp", GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE == hFile) { - err = GetLastError(); - printErrorAndExit("Error at CreateFile",err); + // check command line arguments + if (argc < 2) { + fprintf(stderr, "Error: Can not run without arguments!\nPlease specify '-t {number of threads}' or '-p {number of processes}' and an image filename.\n"); + exit(EXIT_FAILURE); } - /* create the file mapping object */ - hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); - if (NULL == hMap) { - printErrorAndExit("Error at CreateFileMapping", GetLastError()); + + // parse command line arguments + if (scan_argv(argc, argv, "--verbose", arg_value)) { + VERBOSE = TRUE; + } + + 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, "Error: 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, "Error: Please specify number of threads!\n"), + exit(EXIT_FAILURE); + + use_processes = FALSE; + is_worker_process = FALSE; + workers = atoi(arg_value); + + } + + if (!is_worker_process && workers < 1) + fprintf(stderr, "Error: Number of threads/processes must be >0!\n"), + exit(EXIT_FAILURE); + + if (VERBOSE && use_processes) { + fprintf(stdout, "===================================================== "); + if (is_worker_process) + fprintf(stdout, "WORKER-PROCESS\n"); + else + fprintf(stdout, "MASTER-PROCESS\n"); + } + + + // master creates memory mapped file ("empty" image) + if (!is_worker_process) { + + if (argc < 4) { + fprintf(stderr, "Error: Must give filename of image as third argument!\n"); + exit(EXIT_FAILURE); + } + + bmp_filename = argv[3]; + + // 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 + hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, MMAP_NAME); + if (NULL == hMap) { + printErrorAndExit("Error at CreateFileMapping", GetLastError()); + } + + // worker uses existing memory mapped file + } else { + + // open existing mapping object + hMap = OpenFileMapping(FILE_MAP_WRITE, FALSE, MMAP_NAME); + if (NULL == hMap) + 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()); @@ -137,60 +311,172 @@ pDataBitmap = (unsigned char *)((INT_PTR)pData + sizeof(header)); // debugging - printf("pos. of file: %p\n", pData); - printf("pos. of bitmap: %p\n", pDataBitmap); - - // pointer to current pixel - pDataBitmapCurrent = pDataBitmap; + if (VERBOSE) { + fprintf(stdout, "pos. of file: %p\n", pData); + fprintf(stdout, "pos. of bitmap: %p\n", pDataBitmap); + } + + if (use_processes && is_worker_process) { + + if (VERBOSE) + 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("Error while allocating memory for worker arguments via malloc"), exit(1); + + // assign worker's arguments + worker_args[0].start_row = worker_startrow; + worker_args[0].number_of_rows = worker_rows; + worker_args[0].pBitmap = pDataBitmap; + + fractal_create_segment(&worker_args[0]); + + // cleanup mmap-handle + if (!CloseHandle(hMap)) + printErrorAndExit("Error at CloseHandle", GetLastError()); + + return 0; + } + /* - // turn bitmap into white wand + // turn bitmap into white canvas for (offset = 0; offset < 500 * 500 * 3; offset++) { - //pDataBitmap[offset] = 255; - *pDataBitmapCurrent = 255; - pDataBitmapCurrent++; + *pDataBitmap = 255; + pDataBitmap++; } + exit(0); */ - // calculate fractal - for (y=YSIZE-1; y>=0; y--) { - for (x=0; x 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) + // perror("WaitForSingleObject"); + + // close all worker handles + for (worker_index = 0; worker_index < workers; worker_index++) { + if (!CloseHandle(worker_handles[worker_index])) + printErrorAndExit("Error at CloseHandle for worker handles", GetLastError()); + } + + // write the result into the file + if (!FlushViewOfFile(pData, 0)) + printErrorAndExit("Error at UnmapViewOfFile", GetLastError()); + + // remove the mapped file + if (!UnmapViewOfFile(pData)) + printErrorAndExit("Error at UnmapViewOfFile", GetLastError()); + + // cleanup handles + if (!CloseHandle(hMap) || !CloseHandle(hFile) ) + printErrorAndExit("Error at CloseHandle for memory mapped file", GetLastError()); + free(worker_args); + free(worker_handles); + + return 0; + }