--- joko/Uni/BSArch/04/bmp_fractal.c 2006/07/01 22:10:42 1.8 +++ joko/Uni/BSArch/04/bmp_fractal.c 2006/07/02 10:45:02 1.13 @@ -5,7 +5,7 @@ * Uebung 4.4 */ -// $Id: bmp_fractal.c,v 1.8 2006/07/01 22:10:42 joko Exp $ +// $Id: bmp_fractal.c,v 1.13 2006/07/02 10:45:02 joko Exp $ #include #include @@ -15,6 +15,8 @@ #define YSIZE 500 #include "algorithm.h" +BOOL VERBOSE = FALSE; + /* BMP Header */ unsigned char header[54]={0x42,0x4d, // signature BM @@ -47,12 +49,12 @@ 0, NULL )) { - fprintf(stderr,"%s : %s\n",msg,lpMsgBuf); + fprintf(stdout, "%s: %s\n", msg, lpMsgBuf); LocalFree(lpMsgBuf); } else { - fprintf(stderr,"Error at FormatMesage: %d\n",err=GetLastError()); + fprintf(stdout, "Error at FormatMesage: %d\n",err=GetLastError()); } exit(err); } @@ -102,7 +104,7 @@ } WORKERARGS, *PWORKERARGS; // worker thread - main entry function -DWORD WINAPI fractal_thread (LPVOID lpParam) { +DWORD WINAPI fractal_create_segment (LPVOID lpParam) { // thread stuff int thread_id; @@ -117,25 +119,25 @@ // get worker arguments args = (PWORKERARGS)lpParam; - - 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); // calculate pointer to beginning of segment pDataBitmapSegment = (unsigned char *)((INT_PTR)args->pBitmap + (YSIZE - (args->start_row + args->number_of_rows)) * 3 * XSIZE); - printf("segment_start: %p\n", pDataBitmapSegment); + + // debugging + if (VERBOSE) { + 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]); - // debugging - //printf("pointer: %p\n", pDataBitmapCurrent); - // transfer color values to current pixel pDataBitmapSegment[0] = bgr[0]; pDataBitmapSegment[1] = bgr[1]; @@ -145,14 +147,39 @@ pDataBitmapSegment += 3; } - //no padding required because 1500%4 =0 + //no padding required because 1500%4 =0 ??? } - printf("thread finished: %i\n", thread_id); + 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) { + //printf("opt: %s\n", opt_current_name); + opt_current_value = argv[i+1]; + //printf("opt-current-value: %s\n", opt_current_value); + if (opt_current_value != NULL) { + //*opt_value = *argv[i+1]; + *opt_value = *opt_current_value; + //printf("opt-value: %s\n", opt_value); + } + return TRUE; + } + } + return FALSE; +} + int main(int argc, char *argv[]) { @@ -160,33 +187,99 @@ DWORD err; HANDLE hMap, hFile; LPVOID pData; - unsigned char *pDataBitmap, *pDataBitmapCurrent; + unsigned char *pDataBitmap; // workers int workers = 5; int worker_index, worker_rows, worker_startrow; HANDLE *worker_handles; - //struct WorkerArguments *worker_args; PWORKERARGS worker_args; + // threads or processes? + BOOL use_processes = FALSE; + BOOL is_worker_process = FALSE; + + // information for creating processes + STARTUPINFO si; + PROCESS_INFORMATION pi; + char szCmdline[65536]; + + // command line stuff + char arg_option[1024]; + char *arg_value[1024]; + //arg_value = malloc(1024); + + VERBOSE = FALSE; + + // "parse" command line arguments + /* + if (argc >= 2) { + if (strcmp(argv[1], "--worker") == 0) { + is_worker_process = TRUE; + } + } + */ + + //scan_argv(argc, argv, "--worker", &arg_value); + //*arg_value = '\0'; + // parse command line arguments + if (scan_argv(argc, argv, "--worker", arg_value)) { + use_processes = TRUE; + is_worker_process = TRUE; + + } else if (scan_argv(argc, argv, "-p", arg_value)) { + use_processes = TRUE; + is_worker_process = FALSE; + workers = atoi(arg_value); + + } else if (scan_argv(argc, argv, "-t", arg_value)) { + use_processes = FALSE; + is_worker_process = FALSE; + workers = atoi(arg_value); + + } + //printf("value: %s\n", arg_value); + //exit(0); + + + if (VERBOSE && use_processes) { + fprintf(stdout, "===================================================== "); + if (is_worker_process) + fprintf(stdout, "WORKER-PROCESS\n"); + else + fprintf(stdout, "MASTER-PROCESS\n"); + } // create empty bmp-file (black background) - write_blank_file("test.bmp"); + if (!is_worker_process) + write_blank_file("test.bmp"); - /* 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); - } + // master creates memory mapped file + if (!is_worker_process) { + + // 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); + } - /* create the file mapping object */ - hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL); - if (NULL == hMap) { - printErrorAndExit("Error at CreateFileMapping", GetLastError()); + // 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 + hMap = OpenFileMapping(FILE_MAP_WRITE, FALSE, "bmp_fractal"); + 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()); @@ -197,45 +290,72 @@ 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("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); */ - + // allocate memory for bitmap + /* + if ((pDataBitmap = malloc(XSIZE * YSIZE * 3 * sizeof(pDataBitmap[0]))) == NULL) + perror("malloc"), exit(1); + */ + // allocate memory for table of all worker handles - if ((worker_handles = malloc(workers * sizeof worker_handles[0])) == NULL) + if ((worker_handles = malloc(workers * sizeof(worker_handles[0]))) == NULL) perror("malloc"), exit(1); // allocate memory for table of all worker arguments - if ((worker_args = malloc(workers * sizeof worker_args[0])) == NULL) + if ((worker_args = malloc(workers * sizeof(worker_args[0]))) == NULL) perror("malloc"), exit(1); - // allocate memory for table of all worker arguments - /* - worker_args = (PWORKERARGS) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, workers * sizeof(WORKERARGS)); - - if (worker_args == NULL) { - printErrorAndExit("Failed to allocate on heap", GetLastError()); - } - */ - // calculate segments of bitmap for worker threads/processes and start them + // calculate bitmap segment length for workers worker_rows = YSIZE / workers; - printf("rows for each worker: %i\n", worker_rows); + if (VERBOSE) + fprintf(stdout, "rows for each worker: %i\n", worker_rows); + + // start workers for (worker_index = 0; worker_index < workers; worker_index++) { - // debugging: just run with single thread + // debugging: just run single thread //if (worker_index == 1) // continue; @@ -245,29 +365,65 @@ // recalculate number of rows for last worker if (YSIZE mod workers) != 0 if (worker_index == workers - 1) { worker_rows = YSIZE - worker_startrow; - printf("rows for last worker: %i\n", worker_rows); + if (VERBOSE) + fprintf(stdout, "rows for last worker: %i\n", worker_rows); } + // assign each worker's arguments worker_args[worker_index].start_row = worker_startrow; worker_args[worker_index].number_of_rows = worker_rows; worker_args[worker_index].pBitmap = pDataBitmap; - worker_handles[worker_index] = CreateThread( - NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes, - 0, // SIZE_T dwStackSize, - fractal_thread, // LPTHREAD_START_ROUTINE lpStartAddress, - &worker_args[worker_index], // LPVOID lpParameter, - 0, // DWORD dwCreationFlags, - NULL // LPDWORD lpThreadId - ); + if (!use_processes) { + + worker_handles[worker_index] = CreateThread( + NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes, + 0, // SIZE_T dwStackSize, + &fractal_create_segment, // LPTHREAD_START_ROUTINE lpStartAddress, + &worker_args[worker_index], // LPVOID lpParameter, + 0, // DWORD dwCreationFlags, + NULL // LPDWORD lpThreadId + ); + + if (!worker_handles[worker_index]) + printErrorAndExit("CreateThread failed", GetLastError()); + + } else { + + _snprintf(szCmdline, 1023, "%s %s %i %i", argv[0], "--worker", worker_startrow, worker_rows); + if (VERBOSE) + fprintf(stdout, "starting worker process: %s\n", szCmdline); + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + if (!CreateProcess( + NULL, // No module name (use command line) + szCmdline, // Command line + NULL, // Process handle not inheritable + NULL, // Thread handle not inheritable + FALSE, // Set handle inheritance to FALSE + 0, // No creation flags + NULL, // Use parent's environment block + NULL, // Use parent's starting directory + &si, // Pointer to STARTUPINFO structure + &pi // Pointer to PROCESS_INFORMATION structure + )) + printErrorAndExit("CreateProcess failed", GetLastError()); + worker_handles[worker_index] = pi.hProcess; + + } + } // wait for all threads + if (VERBOSE) + fprintf(stdout, "waiting for workers to finish...\n"); if (WaitForMultipleObjects(workers, worker_handles, TRUE, INFINITE) == WAIT_FAILED) perror("WaitForMultipleObjects"); - // debugging: just run with single thread + // debugging: just run single thread //if (WaitForSingleObject(worker_handles[0], INFINITE) == WAIT_FAILED) // perror("WaitForSingleObject"); @@ -275,31 +431,27 @@ 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); } - /* - if (HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, worker_args) != TRUE) { - printErrorAndExit("Call to HeapFree has failed", GetLastError()); - } - */ - + free(worker_args); + free(worker_handles); return 0;