/[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.18 - (show annotations)
Sun Jul 2 12:41:56 2006 UTC (18 years, 2 months ago) by joko
Branch: MAIN
CVS Tags: HEAD
Changes since 1.17: +12 -8 lines
File MIME type: text/plain
more command line error checking

1 /* Betriebssystem & Middleware
2 *
3 * Betriebssystemarchitektur SS 2006
4 *
5 * Uebung 4.4
6 */
7
8 // $Id: bmp_fractal.c,v 1.17 2006/07/02 12:33:35 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, "Error: 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, "Error: 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
245 if (strlen(arg_value) == 0)
246 fprintf(stderr, "Error: Please specify number of threads!\n"),
247 exit(EXIT_FAILURE);
248
249 use_processes = FALSE;
250 is_worker_process = FALSE;
251 workers = atoi(arg_value);
252
253 }
254
255 if (!is_worker_process && workers < 1)
256 fprintf(stderr, "Error: Number of threads/processes must be >0!\n"),
257 exit(EXIT_FAILURE);
258
259 if (VERBOSE && use_processes) {
260 fprintf(stdout, "===================================================== ");
261 if (is_worker_process)
262 fprintf(stdout, "WORKER-PROCESS\n");
263 else
264 fprintf(stdout, "MASTER-PROCESS\n");
265 }
266
267
268 // master creates memory mapped file ("empty" image)
269 if (!is_worker_process) {
270
271 if (argc < 4) {
272 fprintf(stderr, "Error: Must give filename of image as third argument!\n");
273 exit(EXIT_FAILURE);
274 }
275
276 bmp_filename = argv[3];
277
278 // create empty bmp-file (black background)
279 write_blank_file(bmp_filename);
280
281 // open file for reading and writing
282 hFile = CreateFile(bmp_filename, GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
283 if (INVALID_HANDLE_VALUE == hFile) {
284 err = GetLastError();
285 printErrorAndExit("Error at CreateFile",err);
286 }
287
288 // create the file mapping object
289 hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, MMAP_NAME);
290 if (NULL == hMap) {
291 printErrorAndExit("Error at CreateFileMapping", GetLastError());
292 }
293
294 // worker uses existing memory mapped file
295 } else {
296
297 // open existing mapping object
298 hMap = OpenFileMapping(FILE_MAP_WRITE, FALSE, MMAP_NAME);
299 if (NULL == hMap)
300 printErrorAndExit("Error at OpenFileMapping", GetLastError());
301 }
302
303 // map the whole file into the process context
304 pData = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
305 if (NULL == pData) {
306 printErrorAndExit("Error at MapViewOfFile", GetLastError());
307 }
308
309
310 // calculate pointer to beginning of bitmap
311 pDataBitmap = (unsigned char *)((INT_PTR)pData + sizeof(header));
312
313 // debugging
314 if (VERBOSE) {
315 fprintf(stdout, "pos. of file: %p\n", pData);
316 fprintf(stdout, "pos. of bitmap: %p\n", pDataBitmap);
317 }
318
319
320 if (use_processes && is_worker_process) {
321
322 if (VERBOSE)
323 fprintf(stdout, "inside worker-process\n");
324
325 // get segment information from command line
326 worker_startrow = atoi(argv[2]);
327 worker_rows = atoi(argv[3]);
328
329 // allocate memory for one worker's arguments
330 if ((worker_args = malloc(sizeof(worker_args[0]))) == NULL)
331 perror("Error while allocating memory for worker arguments via malloc"), exit(1);
332
333 // assign worker's arguments
334 worker_args[0].start_row = worker_startrow;
335 worker_args[0].number_of_rows = worker_rows;
336 worker_args[0].pBitmap = pDataBitmap;
337
338 fractal_create_segment(&worker_args[0]);
339
340 // cleanup mmap-handle
341 if (!CloseHandle(hMap))
342 printErrorAndExit("Error at CloseHandle", GetLastError());
343
344 return 0;
345 }
346
347 /*
348 // turn bitmap into white canvas
349 for (offset = 0; offset < 500 * 500 * 3; offset++) {
350 *pDataBitmap = 255;
351 pDataBitmap++;
352 }
353 exit(0);
354 */
355
356 // allocate memory for bitmap
357 /*
358 if ((pDataBitmap = malloc(XSIZE * YSIZE * 3 * sizeof(pDataBitmap[0]))) == NULL)
359 perror("malloc"), exit(1);
360 */
361
362 // allocate memory for table of all worker handles
363 if ((worker_handles = malloc(workers * sizeof(worker_handles[0]))) == NULL)
364 perror("Error while allocating memory for worker handles via malloc"), exit(1);
365
366 // allocate memory for table of all worker arguments
367 if ((worker_args = malloc(workers * sizeof(worker_args[0]))) == NULL)
368 perror("Error while allocating memory for worker arguments via malloc"), exit(1);
369
370
371 // calculate bitmap segment length for workers
372 worker_rows = YSIZE / workers;
373 if (VERBOSE)
374 fprintf(stdout, "rows for each worker: %i\n", worker_rows);
375
376 // start workers
377 for (worker_index = 0; worker_index < workers; worker_index++) {
378
379 // debugging: just run single thread
380 //if (worker_index == 1)
381 // continue;
382
383 // number of row to start for each worker
384 worker_startrow = worker_index * worker_rows;
385
386 // recalculate number of rows for last worker if (YSIZE mod workers) != 0
387 if (worker_index == workers - 1) {
388 worker_rows = YSIZE - worker_startrow;
389 if (VERBOSE)
390 fprintf(stdout, "rows for last worker: %i\n", worker_rows);
391 }
392
393 // assign each worker's arguments
394 worker_args[worker_index].start_row = worker_startrow;
395 worker_args[worker_index].number_of_rows = worker_rows;
396 worker_args[worker_index].pBitmap = pDataBitmap;
397
398 if (!use_processes) {
399
400 worker_handles[worker_index] = CreateThread(
401 NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes,
402 0, // SIZE_T dwStackSize,
403 &fractal_create_segment, // LPTHREAD_START_ROUTINE lpStartAddress,
404 &worker_args[worker_index], // LPVOID lpParameter,
405 0, // DWORD dwCreationFlags,
406 NULL // LPDWORD lpThreadId
407 );
408
409 if (!worker_handles[worker_index])
410 printErrorAndExit("CreateThread failed", GetLastError());
411
412 } else {
413
414 if (VERBOSE)
415 verbose_option = "--verbose";
416 _snprintf(szCmdline, MAX_COMMAND_LINE - 1, "%s %s %i %i %s", argv[0], "--worker", worker_startrow, worker_rows, verbose_option);
417 if (VERBOSE)
418 fprintf(stdout, "starting worker process: %s\n", szCmdline);
419
420 // prepare data structures for CreateProcess
421 ZeroMemory( &si, sizeof(si) );
422 si.cb = sizeof(si);
423 ZeroMemory( &pi, sizeof(pi) );
424
425 if (!CreateProcess(
426 NULL, // No module name (use command line)
427 szCmdline, // Command line
428 NULL, // Process handle not inheritable
429 NULL, // Thread handle not inheritable
430 FALSE, // Set handle inheritance to FALSE
431 0, // No creation flags
432 NULL, // Use parent's environment block
433 NULL, // Use parent's starting directory
434 &si, // Pointer to STARTUPINFO structure
435 &pi // Pointer to PROCESS_INFORMATION structure
436 ))
437 printErrorAndExit("CreateProcess failed", GetLastError());
438
439 worker_handles[worker_index] = pi.hProcess;
440
441 }
442
443 }
444
445 if (VERBOSE)
446 fprintf(stdout, "waiting for workers to finish...\n");
447
448 // wait for all workers
449 for (worker_index = 0; worker_index < workers; worker_index += MAXIMUM_WAIT_OBJECTS) {
450 worker_count = ((workers - worker_index) > MAXIMUM_WAIT_OBJECTS) ? MAXIMUM_WAIT_OBJECTS : (workers - worker_index);
451 if (WaitForMultipleObjects(worker_count, &worker_handles[worker_index], TRUE, INFINITE) == WAIT_FAILED)
452 printErrorAndExit("Error at WaitForMultipleObjects", GetLastError());
453 }
454
455 // debugging: just run single thread
456 //if (WaitForSingleObject(worker_handles[0], INFINITE) == WAIT_FAILED)
457 // perror("WaitForSingleObject");
458
459 // close all worker handles
460 for (worker_index = 0; worker_index < workers; worker_index++) {
461 if (!CloseHandle(worker_handles[worker_index]))
462 printErrorAndExit("Error at CloseHandle for worker handles", GetLastError());
463 }
464
465 // write the result into the file
466 if (!FlushViewOfFile(pData, 0))
467 printErrorAndExit("Error at UnmapViewOfFile", GetLastError());
468
469 // remove the mapped file
470 if (!UnmapViewOfFile(pData))
471 printErrorAndExit("Error at UnmapViewOfFile", GetLastError());
472
473 // cleanup handles
474 if (!CloseHandle(hMap) || !CloseHandle(hFile) )
475 printErrorAndExit("Error at CloseHandle for memory mapped file", GetLastError());
476
477 free(worker_args);
478 free(worker_handles);
479
480 return 0;
481
482 }

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