--- joko/Uni/BSArch/04/bmp_fractal.c 2006/06/30 20:39:33 1.1 +++ joko/Uni/BSArch/04/bmp_fractal.c 2006/07/02 01:51:26 1.10 @@ -4,6 +4,10 @@ * * Uebung 4.4 */ + +// $Id: bmp_fractal.c,v 1.10 2006/07/02 01:51:26 joko Exp $ + +#include #include #include @@ -11,7 +15,12 @@ #define YSIZE 500 #include "algorithm.h" -/* BMP Header +#define MASTER -1 + +BOOL VERBOSE = TRUE; + + +/* BMP Header */ unsigned char header[54]={0x42,0x4d, // signature BM 0xe6,0x71,0x0b,0x0, // filesize 750054 0x0,0x0,0x0,0x0, // reserved @@ -28,94 +37,358 @@ 0x0,0x0,0x0,0x0, // number of colortables 0x0,0x0,0x0,0x0 // number of important colors }; -*/ -int main(int argc, char *argv[]) -{ - FILE *fd; - int len,x,y; - char bgr[3]; - short svalue; - int lvalue; - unsigned char header[54],*ptr=&header[0]; - - fd=fopen("test.bmp","wb+"); - if(NULL==fd) - { - perror("open"); exit(1); - } -/* Der folgende Abschnitt dient nur zur information und kann durch - schreiben der auskommentierten Variable header ersetzt werden */ - svalue=0x4d42; - memcpy(ptr,&svalue,2);//signatur - ptr+=2; - lvalue=XSIZE*YSIZE*3+54; - memcpy(ptr,&lvalue,4); //filesize - ptr+=4; - lvalue=0; - memcpy(ptr,&lvalue,4);//reserved - ptr+=4; - lvalue=54; - memcpy(ptr,&lvalue,4);//image offset - ptr+=4; - lvalue=40; - memcpy(ptr,&lvalue,4);//size of header follows - ptr+=4; - lvalue=XSIZE; - memcpy(ptr,&lvalue,4);//with of image - ptr+=4; - lvalue=YSIZE; - memcpy(ptr,&lvalue,4); //height of image - ptr+=4; - svalue=1; - memcpy(ptr,&svalue,2); //number of planes - ptr+=2; - svalue=24; - memcpy(ptr,&svalue,2); //number of pixel - ptr+=2; - lvalue=0; //compression - memcpy(ptr,&lvalue,4); //compression - ptr+=4; - lvalue=XSIZE*YSIZE*3; - memcpy(ptr,&lvalue,4); //size of image - ptr+=4; - lvalue=0; - memcpy(ptr,&lvalue,4); //xres - ptr+=4; - lvalue=0; - memcpy(ptr,&lvalue,4); //yres - ptr+=4; - lvalue=0; - memcpy(ptr,&lvalue,4); //number of colortables - ptr+=4; - lvalue=0; - memcpy(ptr,&lvalue,4); //number of important colors - ptr+=4; -/* Ende Information */ - - len=fwrite(header,1,sizeof(header),fd); //write header - - if(-1==len || len!=sizeof(header)) - { - perror("write"); - exit(2); - } - - for(y=YSIZE-1;y>=0;y--) - { - for(x=0;xpBitmap + (YSIZE - (args->start_row + args->number_of_rows)) * 3 * XSIZE); + + // 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); + } + + // 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); + 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]); + + // 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) + printf("thread finished: %i\n", thread_id); + return 0; + +} + + +int main(int argc, char *argv[]) { + + // MMF support + DWORD err; + HANDLE hMap, hFile; + LPVOID pData; + unsigned char *pDataBitmap; + + // workers + int workers = 5; + int worker_index, worker_rows, worker_startrow; + HANDLE *worker_handles; + PWORKERARGS worker_args; + + // threads or processes? + BOOL use_processes = TRUE; + int worker_id = MASTER; + + // information for creating processes + STARTUPINFO si; + PROCESS_INFORMATION pi; + char szCmdline[1024]; + + + // "parse" command line arguments + if (argc >= 2) { + worker_id = atoi(argv[1]); + } + + if (VERBOSE) { + printf("==============================================================\n"); + printf("worker-id: %i\n", worker_id); + } + + // create empty bmp-file (black background) + if (worker_id == MASTER) + write_blank_file("test.bmp"); + + if (worker_id == MASTER) { + + /* 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, "bmp_fractal"); + if (NULL == hMap) { + printErrorAndExit("Error at CreateFileMapping", GetLastError()); + } + + } 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 */ + pData = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); + if (NULL == pData) { + printErrorAndExit("Error at MapViewOfFile", GetLastError()); + } + + + // calculate pointer to beginning of bitmap + pDataBitmap = (unsigned char *)((INT_PTR)pData + sizeof(header)); + + // debugging + if (VERBOSE) { + printf("pos. of file: %p\n", pData); + printf("pos. of bitmap: %p\n", pDataBitmap); + } + + + if (use_processes && worker_id != MASTER) { + + if (VERBOSE) + printf("inside worker-process\n"); + + worker_index = worker_id; + + 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]); + return 0; + } + + /* + // turn bitmap into white canvas + for (offset = 0; offset < 500 * 500 * 3; offset++) { + *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) + perror("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); + + + // calculate bitmap segment length for workers + worker_rows = YSIZE / workers; + if (VERBOSE) + printf("rows for each worker: %i\n", worker_rows); + + // start workers + for (worker_index = 0; worker_index < workers; worker_index++) { + + // debugging: just run single thread + //if (worker_index == 1) + // continue; + + // number of row to start for each worker + worker_startrow = worker_index * worker_rows; + + // recalculate number of rows for last worker if (YSIZE mod workers) != 0 + if (worker_index == workers - 1) { + worker_rows = YSIZE - worker_startrow; + if (VERBOSE) + printf("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; + + 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 %i %i %i", argv[0], worker_index + 1, worker_startrow, worker_rows); + 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) + printf("waiting for workers to finish...\n"); + if (WaitForMultipleObjects(workers, worker_handles, TRUE, INFINITE) == WAIT_FAILED) + perror("WaitForMultipleObjects"); + + // 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++) + CloseHandle(worker_handles[worker_index]); + + /* write the result into the file */ + if (!FlushViewOfFile(pData, 0)) { + err = GetLastError(); + printErrorAndExit("Error at UnmapViewOfFile", err); + } + + /* remove the mapped file */ + if (!UnmapViewOfFile(pData)) { + err = GetLastError(); + printErrorAndExit("Error at UnmapViewOfFile", err); + exit(err); + } + + /* cleanup handles */ + if (!CloseHandle(hMap) || !CloseHandle(hFile) ) { + err = GetLastError(); + printErrorAndExit("Error at CloseHandle", err); + } + + free(worker_args); + free(worker_handles); + + return 0; + }