/[cvs]/joko/Uni/BSArch/04/bmp_fractal.c
ViewVC logotype

Contents of /joko/Uni/BSArch/04/bmp_fractal.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (show annotations)
Sun Jul 2 12:33:35 2006 UTC (18 years, 2 months ago) by joko
Branch: MAIN
Changes since 1.16: +30 -24 lines
File MIME type: text/plain
more error handling

1 /* Betriebssystem & Middleware
2 *
3 * Betriebssystemarchitektur SS 2006
4 *
5 * Uebung 4.4
6 */
7
8 // $Id: bmp_fractal.c,v 1.16 2006/07/02 12:21:01 joko Exp $
9
10 #include <windows.h>
11 #include <stdio.h>
12 #include <errno.h>
13
14 #define XSIZE 500
15 #define YSIZE 500
16 #include "algorithm.h"
17
18 #define MAX_COMMAND_LINE 65536
19 #define MMAP_NAME "bmp_fractal"
20
21 BOOL VERBOSE = FALSE;
22
23
24 /* BMP Header */
25 unsigned char header[54]={0x42,0x4d, // signature BM
26 0xe6,0x71,0x0b,0x0, // filesize 750054
27 0x0,0x0,0x0,0x0, // reserved
28 0x36,0x0,0x0,0x0, // image offset 54
29 0x28,0x0,0x0,0x0, // size of header follows 40
30 0xf4,0x1,0x0,0x0, // with of image 500
31 0xf4,0x1,0x0,0x0, // height of image 500
32 0x1,0x0, // number of planes 1
33 0x18,0x0, // number of pixel 24
34 0x0,0x0,0x0,0x0, // compression
35 0xb0,0x71,0x0b,0x0, // size of image 750000
36 0x0,0x0,0x0,0x0, // xres
37 0x0,0x0,0x0,0x0, // yres
38 0x0,0x0,0x0,0x0, // number of colortables
39 0x0,0x0,0x0,0x0 // number of important colors
40 };
41
42
43 void printErrorAndExit(const char *msg, DWORD err) {
44 LPSTR lpMsgBuf;
45 if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
46 FORMAT_MESSAGE_FROM_SYSTEM |
47 FORMAT_MESSAGE_IGNORE_INSERTS,
48 NULL,
49 err,
50 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
51 (LPTSTR) &lpMsgBuf,
52 0,
53 NULL ))
54 {
55 fprintf(stderr, "%s: %s\n", msg, lpMsgBuf);
56 LocalFree(lpMsgBuf);
57 }
58 else
59 {
60 fprintf(stderr, "Error at FormatMesage: %d\n",err=GetLastError());
61 }
62 exit(err);
63 }
64
65
66 void write_blank_file(char *filename) {
67
68 FILE *fd;
69 int len, i, img_size;
70
71 // open file handle
72 fd = fopen(filename, "wb+");
73 if (NULL == fd) {
74 perror("Error while opening file for writing");
75 exit(1);
76 }
77
78 // write bmp header to file
79 len = fwrite(header, 1, sizeof(header), fd);
80
81 // error checking
82 if (-1 == len || len != sizeof(header)) {
83 perror("Error while writing header to file");
84 exit(2);
85 }
86
87 // write three null-bytes for each pixel to file to create a black picture
88 img_size = XSIZE * YSIZE;
89 for (i = 0; i < img_size; i++) {
90 len = fwrite("\0\0\0", 1, 3, fd);
91 if (-1 == len || len != 3) {
92 perror("Error while writing data to file");
93 exit(4);
94 }
95 }
96
97 // close file handle
98 if (fclose(fd) != 0) {
99 perror("Error while closing file handle");
100 exit(1);
101 }
102 }
103
104
105 // arguments for each thread
106 typedef struct _WorkerArguments {
107 int start_row;
108 int number_of_rows;
109 unsigned char * pBitmap;
110 } WORKERARGS, *PWORKERARGS;
111
112 // worker thread - main entry function
113 DWORD WINAPI fractal_create_segment (LPVOID lpParam) {
114
115 // thread stuff
116 int thread_id;
117 PWORKERARGS args;
118 unsigned char *pDataBitmapSegment;
119
120 // fractal calculation
121 int x, y;
122 char bgr[3];
123
124 // get worker arguments
125 args = (PWORKERARGS)lpParam;
126
127 // calculate pointer to beginning of segment
128 pDataBitmapSegment = (unsigned char *)((INT_PTR)args->pBitmap + (YSIZE - (args->start_row + args->number_of_rows)) * 3 * XSIZE);
129
130 // debugging
131 if (VERBOSE) {
132 thread_id = GetCurrentThreadId();
133 fprintf(stdout, "----------------------------------------------\n");
134 fprintf(stdout, "thread_id: %i\n", thread_id);
135 fprintf(stdout, "arg.start_row: %i\n", args->start_row);
136 fprintf(stdout, "arg.number_of_rows: %i\n", args->number_of_rows);
137 fprintf(stdout, "segment_start: %p\n", pDataBitmapSegment);
138 }
139
140 // calculate fractal
141 for (y = (args->start_row + args->number_of_rows) - 1; y >= args->start_row; y--) {
142 //fprintf(stdout, "calc: thread=%i; y=%i limits: %i,%i p: %p\n", thread_id, y, args->start_row, args->number_of_rows, pDataBitmapSegment);
143 for (x = 0; x < XSIZE; x++) {
144
145 // call to function in static linked library
146 getColorValuesAt(x * (2.0 / XSIZE) - 1.5, y * (2.0 / YSIZE) - 1.0, &bgr[2], &bgr[1], &bgr[0]);
147
148 // transfer color values to current pixel
149 pDataBitmapSegment[0] = bgr[0];
150 pDataBitmapSegment[1] = bgr[1];
151 pDataBitmapSegment[2] = bgr[2];
152
153 // move pointer to next pixel
154 pDataBitmapSegment += 3;
155
156 }
157 //no padding required because 1500%4 =0 ???
158 }
159
160 if (VERBOSE)
161 fprintf(stdout, "thread finished: %i\n", thread_id);
162 return 0;
163
164 }
165
166 BOOL scan_argv(int argc, char *argv[], char opt_name[], char *opt_value) {
167 int i;
168 char * opt_current_name;
169 char * opt_current_value;
170
171 //printf("searching for: '%s'\n", opt_name);
172
173 for (i = 1; i < argc; i++) {
174 opt_current_name = argv[i];
175 if (strcmp(opt_current_name, opt_name) == 0) {
176 opt_current_value = argv[i+1];
177 if (opt_current_value != NULL) {
178 strcpy(opt_value, opt_current_value);
179 }
180 return TRUE;
181 }
182 }
183 return FALSE;
184 }
185
186
187 int main(int argc, char *argv[]) {
188
189 // MMF support
190 DWORD err;
191 HANDLE hMap, hFile;
192 LPVOID pData;
193 unsigned char *pDataBitmap;
194
195 // workers
196 int workers;
197 int worker_index, worker_rows, worker_startrow;
198 HANDLE *worker_handles;
199 PWORKERARGS worker_args;
200 int worker_count;
201
202 // threads or processes?
203 BOOL use_processes = FALSE;
204 BOOL is_worker_process = FALSE;
205
206 // information for creating processes
207 STARTUPINFO si;
208 PROCESS_INFORMATION pi;
209 char szCmdline[MAX_COMMAND_LINE];
210
211 // command line stuff
212 char arg_option[1024];
213 char arg_value[1024];
214 char *bmp_filename;
215 char *verbose_option = "";
216
217
218 // check command line arguments
219 if (argc < 2) {
220 fprintf(stderr, "Can not run without arguments!\nPlease specify '-t {number of threads}' or '-p {number of processes}' and an image filename.\n");
221 exit(EXIT_FAILURE);
222 }
223
224
225 // parse command line arguments
226 if (scan_argv(argc, argv, "--verbose", arg_value)) {
227 VERBOSE = TRUE;
228 }
229
230 if (scan_argv(argc, argv, "--worker", arg_value)) {
231 use_processes = TRUE;
232 is_worker_process = TRUE;
233
234 } else if (scan_argv(argc, argv, "-p", arg_value)) {
235 if (strlen(arg_value) == 0) {
236 fprintf(stderr, "Please specify number of processes!\n");
237 exit(EXIT_FAILURE);
238 }
239 use_processes = TRUE;
240 is_worker_process = FALSE;
241 workers = atoi(arg_value);
242
243 } else if (scan_argv(argc, argv, "-t", arg_value)) {
244 if (strlen(arg_value) == 0) {
245 fprintf(stderr, "Please specify number of threads!\n");
246 exit(EXIT_FAILURE);
247 }
248 use_processes = FALSE;
249 is_worker_process = FALSE;
250 workers = atoi(arg_value);
251
252 }
253
254
255 if (VERBOSE && use_processes) {
256 fprintf(stdout, "===================================================== ");
257 if (is_worker_process)
258 fprintf(stdout, "WORKER-PROCESS\n");
259 else
260 fprintf(stdout, "MASTER-PROCESS\n");
261 }
262
263
264 // master creates memory mapped file ("empty" image)
265 if (!is_worker_process) {
266
267 if (argc < 4) {
268 fprintf(stderr, "Must give filename of image as third argument!\n");
269 exit(EXIT_FAILURE);
270 }
271
272 bmp_filename = argv[3];
273
274 // create empty bmp-file (black background)
275 write_blank_file(bmp_filename);
276
277 // open file for reading and writing
278 hFile = CreateFile(bmp_filename, GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
279 if (INVALID_HANDLE_VALUE == hFile) {
280 err = GetLastError();
281 printErrorAndExit("Error at CreateFile",err);
282 }
283
284 // create the file mapping object
285 hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, MMAP_NAME);
286 if (NULL == hMap) {
287 printErrorAndExit("Error at CreateFileMapping", GetLastError());
288 }
289
290 // worker uses existing memory mapped file
291 } else {
292
293 // open existing mapping object
294 hMap = OpenFileMapping(FILE_MAP_WRITE, FALSE, MMAP_NAME);
295 if (NULL == hMap)
296 printErrorAndExit("Error at OpenFileMapping", GetLastError());
297 }
298
299 // map the whole file into the process context
300 pData = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
301 if (NULL == pData) {
302 printErrorAndExit("Error at MapViewOfFile", GetLastError());
303 }
304
305
306 // calculate pointer to beginning of bitmap
307 pDataBitmap = (unsigned char *)((INT_PTR)pData + sizeof(header));
308
309 // debugging
310 if (VERBOSE) {
311 fprintf(stdout, "pos. of file: %p\n", pData);
312 fprintf(stdout, "pos. of bitmap: %p\n", pDataBitmap);
313 }
314
315
316 if (use_processes && is_worker_process) {
317
318 if (VERBOSE)
319 fprintf(stdout, "inside worker-process\n");
320
321 // get segment information from command line
322 worker_startrow = atoi(argv[2]);
323 worker_rows = atoi(argv[3]);
324
325 // allocate memory for one worker's arguments
326 if ((worker_args = malloc(sizeof(worker_args[0]))) == NULL)
327 perror("Error while allocating memory for worker arguments via malloc"), exit(1);
328
329 // assign worker's arguments
330 worker_args[0].start_row = worker_startrow;
331 worker_args[0].number_of_rows = worker_rows;
332 worker_args[0].pBitmap = pDataBitmap;
333
334 fractal_create_segment(&worker_args[0]);
335
336 // cleanup mmap-handle
337 if (!CloseHandle(hMap))
338 printErrorAndExit("Error at CloseHandle", GetLastError());
339
340 return 0;
341 }
342
343 /*
344 // turn bitmap into white canvas
345 for (offset = 0; offset < 500 * 500 * 3; offset++) {
346 *pDataBitmap = 255;
347 pDataBitmap++;
348 }
349 exit(0);
350 */
351
352 // allocate memory for bitmap
353 /*
354 if ((pDataBitmap = malloc(XSIZE * YSIZE * 3 * sizeof(pDataBitmap[0]))) == NULL)
355 perror("malloc"), exit(1);
356 */
357
358 // allocate memory for table of all worker handles
359 if ((worker_handles = malloc(workers * sizeof(worker_handles[0]))) == NULL)
360 perror("Error while allocating memory for worker handles via malloc"), exit(1);
361
362 // allocate memory for table of all worker arguments
363 if ((worker_args = malloc(workers * sizeof(worker_args[0]))) == NULL)
364 perror("Error while allocating memory for worker arguments via malloc"), exit(1);
365
366
367 // calculate bitmap segment length for workers
368 worker_rows = YSIZE / workers;
369 if (VERBOSE)
370 fprintf(stdout, "rows for each worker: %i\n", worker_rows);
371
372 // start workers
373 for (worker_index = 0; worker_index < workers; worker_index++) {
374
375 // debugging: just run single thread
376 //if (worker_index == 1)
377 // continue;
378
379 // number of row to start for each worker
380 worker_startrow = worker_index * worker_rows;
381
382 // recalculate number of rows for last worker if (YSIZE mod workers) != 0
383 if (worker_index == workers - 1) {
384 worker_rows = YSIZE - worker_startrow;
385 if (VERBOSE)
386 fprintf(stdout, "rows for last worker: %i\n", worker_rows);
387 }
388
389 // assign each worker's arguments
390 worker_args[worker_index].start_row = worker_startrow;
391 worker_args[worker_index].number_of_rows = worker_rows;
392 worker_args[worker_index].pBitmap = pDataBitmap;
393
394 if (!use_processes) {
395
396 worker_handles[worker_index] = CreateThread(
397 NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes,
398 0, // SIZE_T dwStackSize,
399 &fractal_create_segment, // LPTHREAD_START_ROUTINE lpStartAddress,
400 &worker_args[worker_index], // LPVOID lpParameter,
401 0, // DWORD dwCreationFlags,
402 NULL // LPDWORD lpThreadId
403 );
404
405 if (!worker_handles[worker_index])
406 printErrorAndExit("CreateThread failed", GetLastError());
407
408 } else {
409
410 if (VERBOSE)
411 verbose_option = "--verbose";
412 _snprintf(szCmdline, MAX_COMMAND_LINE - 1, "%s %s %i %i %s", argv[0], "--worker", worker_startrow, worker_rows, verbose_option);
413 if (VERBOSE)
414 fprintf(stdout, "starting worker process: %s\n", szCmdline);
415
416 // prepare data structures for CreateProcess
417 ZeroMemory( &si, sizeof(si) );
418 si.cb = sizeof(si);
419 ZeroMemory( &pi, sizeof(pi) );
420
421 if (!CreateProcess(
422 NULL, // No module name (use command line)
423 szCmdline, // Command line
424 NULL, // Process handle not inheritable
425 NULL, // Thread handle not inheritable
426 FALSE, // Set handle inheritance to FALSE
427 0, // No creation flags
428 NULL, // Use parent's environment block
429 NULL, // Use parent's starting directory
430 &si, // Pointer to STARTUPINFO structure
431 &pi // Pointer to PROCESS_INFORMATION structure
432 ))
433 printErrorAndExit("CreateProcess failed", GetLastError());
434
435 worker_handles[worker_index] = pi.hProcess;
436
437 }
438
439 }
440
441 if (VERBOSE)
442 fprintf(stdout, "waiting for workers to finish...\n");
443
444 // wait for all workers
445 for (worker_index = 0; worker_index < workers; worker_index += MAXIMUM_WAIT_OBJECTS) {
446 worker_count = ((workers - worker_index) > MAXIMUM_WAIT_OBJECTS) ? MAXIMUM_WAIT_OBJECTS : (workers - worker_index);
447 if (WaitForMultipleObjects(worker_count, &worker_handles[worker_index], TRUE, INFINITE) == WAIT_FAILED)
448 printErrorAndExit("Error at WaitForMultipleObjects", GetLastError());
449 }
450
451 // debugging: just run single thread
452 //if (WaitForSingleObject(worker_handles[0], INFINITE) == WAIT_FAILED)
453 // perror("WaitForSingleObject");
454
455 // close all worker handles
456 for (worker_index = 0; worker_index < workers; worker_index++) {
457 if (!CloseHandle(worker_handles[worker_index]))
458 printErrorAndExit("Error at CloseHandle for worker handles", GetLastError());
459 }
460
461 // write the result into the file
462 if (!FlushViewOfFile(pData, 0))
463 printErrorAndExit("Error at UnmapViewOfFile", GetLastError());
464
465 // remove the mapped file
466 if (!UnmapViewOfFile(pData))
467 printErrorAndExit("Error at UnmapViewOfFile", GetLastError());
468
469 // cleanup handles
470 if (!CloseHandle(hMap) || !CloseHandle(hFile) )
471 printErrorAndExit("Error at CloseHandle for memory mapped file", GetLastError());
472
473 free(worker_args);
474 free(worker_handles);
475
476 return 0;
477
478 }

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed