|
|
1.1 root 1: /*
2: * REMOTE.C --
3: *
4: * Code to do the remote calculations for the Windows Mandelbrot Set
5: * distributed drawing program.
6: *
7: * Copyright (C) 1990 Microsoft Corporation.
8: *
9: * Information coming into this module (via API calls) is based on
10: * upper-left being (0,0) (the Windows standard). We translate that
11: * to PM standard (lower-left is (0,0) ) before we ship it out onto
12: * the net, and we do reverse translations accordingly.
13: *
14: * The iteration data is passed back to the main window procedure
15: * (by means of a WM_PAINTLINE message) which draws the picture.
16: *
17: * A word about the shared buffer: multiple buffers could be used, but
18: * a single one is used. The buffer is requested in this code, and
19: * then released after the data has been drawn (in PaintLine() in
20: * mandel.c). So long as the painting is done quickly, this is efficient.
21: *
22: * This code sample is provided for demonstration purposes only.
23: * Microsoft makes no warranty, either express or implied,
24: * as to its usability in any given situation.
25: */
26:
27:
28: #include <string.h>
29: #include <stdio.h>
30: #include <fcntl.h>
31: #include <sys\types.h>
32: #include <sys\stat.h>
33: #include <share.h>
34: #include <io.h>
35: #include <malloc.h>
36:
37: #include <windows.h>
38:
39: #ifdef RPC
40: #include <rpc.h>
41: #include "mdlrpc.h"
42: #endif
43:
44: #include "mandel.h"
45: /*
46: * Tuning paramters
47: */
48: #define SVR_TABLE_SZ 20
49: #define MAX_PIPENAME_SZ CCHMAXPATH
50:
51:
52: /*
53: * Manifests, to keep everything neat.
54: */
55:
56: extern int errno; // errno from c runtime
57:
58: /*
59: * Data structures
60: */
61: extern svr_table SvrTable[]; // the table
62: extern int SvrTableSz; // # of objects in it
63: char pszFail[255];
64:
65:
66: // Do we do local work?
67: BOOL fLocalWork = TRUE;
68: BOOL fRemoteWork = FALSE;
69:
70: static int fDisplay = TRUE; /* display a message box for debug */
71:
72: // Picture information
73:
74: int cPictureID = 0; // picture id, in case we reset in the middle
75: static CPOINT cptLL; // upper-left
76: static double dPrecision; // precision of draw
77: static LONGRECT rclPicture; // rectangle defining client window
78: static DWORD dwCurrentLine; // next line to be drawn
79: static DWORD dwThreshold; // threshold for iterations
80:
81:
82: static char szLocal[] = "Local machine";
83: #ifdef RPC
84: RPC_STATUS status; // returned by RPC API function
85: #endif
86: /*
87: * function prototypes for local procs
88: */
89:
90: DWORD CalcThreshold( double );
91:
92:
93:
94: /*
95: * InitRemote --
96: *
97: * This function initializes everything for our remote connections.
98: * It gets the local wksta name (making sure the wksta is started)
99: * and it creates the mailslot with which to collect replies to our poll.
100: *
101: * RETURNS
102: *
103: * TRUE - initialization succeeded
104: * FALSE - initialization failed, can't go on
105: */
106:
107:
108: BOOL
109: InitRemote( HWND hWnd )
110: {
111: #ifndef RPC
112: UNREFERENCED_PARAMETER(hWnd);
113: #endif
114:
115: // set up our local entry
116: SvrTableSz++;
117: strcpy(SvrTable[0].name, szLocal);
118: SvrTable[0].iStatus = SS_LOCAL;
119:
120: // set up remote entries
121: #ifdef RPC
122: mdlrpc_ProtocolStack.TransportType = RPC_TRANSPORT_NAMEPIPE;
123: mdlrpc_ProtocolStack.TransportInfo = "\\device\\namedpipe\\mdlrpc";
124: mdlrpc_ProtocolStack.TransportInfoLength = \
125: strlen(mdlrpc_ProtocolStack.TransportInfo) + 1;
126: // add 1 for terminating null
127:
128: /* Call the Microsoft RPC V1.0 Alpha API function that lets */
129: /* the client establish a connection with the server. */
130: /* NOTE: This API function will be replaced in future */
131: /* releases by the standard DCE RPC function. */
132: status = RpcBindToInterface(&mdlrpc_ProtocolStack,
133: 0L,
134: &hMandel);
135: if (status) {
136: sprintf(pszFail, "RpcBindToInterface returned 0x%x\n", status);
137: strcat(pszFail, "Please verify that the server side of the Mandel distributed application is running.\n");
138: MessageBox(hWnd, pszFail, "Mandelbrot RPC Server Not Started",
139: MB_ICONHAND | MB_SYSTEMMODAL);
140: PostMessage(hWnd, WM_DESTROY, 0, 0L);
141: return FALSE;
142: }
143: #endif
144:
145: // good, we succeeded
146: return TRUE;
147: }
148:
149:
150: /*
151: * CheckDrawStatus --
152: *
153: * This function does a check of all buffers being drawn.
154: *
155: * If it finds an idle pipe, and there is work to be done, it assigns
156: * a line, and writes out the request.
157: * If it finds a read-pending pipe, it checks if the read has completed.
158: * If it has, it is read and a message is sent so the read data can
159: * be processed.
160: *
161: * RETURNS
162: * TRUE - we did a piece of work
163: * FALSE - we could not find any work to do.
164: */
165:
166: BOOL CheckDrawStatus( HWND hwnd)
167: {
168:
169: static int iWork = 0;
170: int iLast;
171: CALCBUF cb;
172: PDWORD pbBuf;
173:
174: // If no pipes, forget it
175: if (SvrTableSz == 0)
176: return FALSE;
177:
178: // Move on from where we left off
179:
180: iLast = iWork;
181:
182: while ( TRUE )
183: {
184: iWork++;
185:
186: if (iWork == SvrTableSz)
187: iWork = 0;
188:
189: // Check the status
190: switch(SvrTable[iWork].iStatus) {
191:
192: case SS_PAINTING:
193: break;
194:
195: case SS_IDLE:
196: // Idle; assign it a piece of work
197: if ((long)dwCurrentLine > rclPicture.xRight)
198: break;
199:
200: if (!fRemoteWork)
201: break;
202: // cb is of type CALCBUF;
203: // rectangle, precision, threshold and complex point
204: cb.rclDraw.xLeft = dwCurrentLine;
205: cb.rclDraw.xRight = dwCurrentLine + iLines - 1;
206: cb.rclDraw.yTop = rclPicture.yTop;
207: cb.rclDraw.yBottom = rclPicture.yBottom;
208: cb.dblPrecision = dPrecision;
209: cb.dwThreshold = dwThreshold;
210: cb.cptLL = cptLL;
211:
212: SvrTable[iWork].dwLine = dwCurrentLine;
213: dwCurrentLine += iLines;
214: SvrTable[iWork].iStatus = SS_READPENDING;
215: SvrTable[iWork].cPicture = cPictureID;
216: SvrTable[iWork].cLines = iLines;
217:
218: return TRUE;
219:
220: case SS_LOCAL:
221: // Do a chunk of work locally
222:
223: if ((long)dwCurrentLine > rclPicture.xRight) {
224: if (fContinueZoom == TRUE) {
225: if ((fZoomIn == TRUE) && (dPrec < (double)MINPREC))
226: fZoomIn = FALSE; // start zooming out
227: if ((fZoomIn == FALSE) && (dPrec > (double)MAXPREC))
228: fZoomIn = TRUE;
229: if (fZoomIn) {
230: CountHistogram();
231: rcZoom.top = iHistMaxJ * (WIDTH/4);
232: rcZoom.bottom = rcZoom.top + (WIDTH/4) - 1;
233: rcZoom.left = iHistMaxI * (HEIGHT/4);
234: rcZoom.right = rcZoom.left + (HEIGHT/4) - 1;
235: fRectDefined = TRUE;
236: PostMessage(hwnd, WM_COMMAND, IDM_ZOOMIN, 0L);
237: }
238: else
239: PostMessage(hwnd, WM_COMMAND, IDM_ZOOMOUT, 0L);
240: }
241: break;
242: }
243:
244: if (!TakeDrawBuffer())
245: break;
246:
247: pbBuf = GetDrawBuffer();
248:
249: cb.rclDraw.xLeft = dwCurrentLine;
250: cb.rclDraw.xRight = dwCurrentLine+ iLines-1;
251: cb.rclDraw.yTop = rclPicture.yTop;
252: cb.rclDraw.yBottom = rclPicture.yBottom;
253:
254:
255: MandelCalc(&cptLL,
256: &(cb.rclDraw),
257: dPrecision,
258: dwThreshold,
259: (PLINEBUF)pbBuf);
260:
261: FreeDrawBuffer();
262:
263: SvrTable[iWork].cPicture = cPictureID;
264: SvrTable[iWork].dwLine = dwCurrentLine;
265: SvrTable[iWork].cLines = iLines;
266:
267: PostMessage(hwnd, WM_PAINTLINE,
268: (UINT)iWork,
269: 0L);
270: dwCurrentLine += iLines;
271: return TRUE;
272:
273: }
274:
275:
276: // If we made the full loop, we're done
277: if (iWork == iLast)
278: return FALSE;
279: }
280: }
281:
282:
283: /*
284: * SetNewCalc --
285: *
286: * This sets up new information for a drawing and
287: * updates the drawing ID so any calculations in progress will not
288: * be mixed in.
289: */
290:
291: void SetNewCalc( CPOINT cptUL, double dPrec, RECT rc)
292: {
293:
294: /*
295: * First, the base point. We need to translate from upper left to
296: * lower left.
297: */
298:
299: cptLL.real = cptUL.real;
300: cptLL.imag = cptUL.imag - (dPrec * (rc.bottom - rc.top));
301:
302: // Now the precision
303: dPrecision = dPrec;
304:
305: // The rectangle. Once again, translate.
306: rclPicture.xLeft = (long) rc.left;
307: rclPicture.xRight = (long) rc.right;
308: rclPicture.yBottom = (long) rc.top;
309: rclPicture.yTop = (long) rc.bottom;
310:
311: // Current line, start of drawing
312: dwCurrentLine = rclPicture.xLeft;
313:
314: dwThreshold = CalcThreshold(dPrecision);
315:
316:
317: }
318:
319: void IncPictureID(void)
320: {
321: cPictureID++;
322: }
323:
324: /*
325: * CheckDrawing --
326: *
327: * Just a sanity check here -- a function to check to make sure that we're
328: * on the right drawing
329: */
330:
331: BOOL
332: CheckDrawingID( int id)
333: {
334: return (id == cPictureID) ? TRUE : FALSE;
335: }
336:
337:
338: /*
339: * TakeDrawBuffer/ GetDrawBuffer/ FreeDrawBuffer / ReturnDrawBuffer
340: *
341: * These functions hide a handle to a buffer of memory.
342: *
343: * TakeDrawBuffer ensures only one pipe read at a time.
344: * GetDrawBuffer locks the handle and returns a pointer.
345: * FreeDrawBuffer unlocks the handle.
346: * ReturnDrawBuffer unlocks the handle and lets another pipe read go.
347: */
348:
349: static BOOL fBufferTaken = FALSE;
350: static HANDLE hSharedBuf = NULL;
351:
352:
353: BOOL
354: TakeDrawBuffer( void )
355: {
356:
357: if (fBufferTaken)
358: {
359: return FALSE;
360: }
361:
362: if (hSharedBuf == NULL)
363: {
364: hSharedBuf = LocalAlloc(LMEM_MOVEABLE, MAX_BUFSIZE);
365: if (hSharedBuf == NULL)
366: return FALSE;
367: }
368: fBufferTaken = TRUE;
369: return TRUE;
370: }
371:
372:
373:
374: PDWORD
375: GetDrawBuffer( void )
376: {
377:
378: if (hSharedBuf == NULL)
379: return NULL;
380:
381: return (PDWORD) LocalLock(hSharedBuf);
382: }
383:
384:
385:
386: void
387: FreeDrawBuffer( void )
388: {
389: LocalUnlock(hSharedBuf);
390: }
391:
392:
393: void
394: ReturnDrawBuffer( void )
395: {
396: fBufferTaken = FALSE;
397: }
398:
399:
400:
401: /*
402: * CalcThreshold --
403: *
404: * We need an iteration threshold beyond which we give up. We want it to
405: * increase the farther we zoom in. This code generates a threshold value
406: * based on the precision of drawing.
407: *
408: * RETURNS
409: *
410: * threshold calculated based on precision
411: */
412:
413:
414: DWORD CalcThreshold(double precision)
415: {
416: DWORD thres = 25;
417: double multiplier = (double) 100;
418:
419: /* for every 100, multiply by 2 */
420: while ( (precision *= multiplier) < (double)1)
421: thres *= 2;
422:
423: return thres;
424: }
425:
426:
427:
428: /*
429: * QueryThreshold --
430: *
431: * Callback for finding out what the current drawing's threshold is.
432: */
433:
434: DWORD QueryThreshold( void )
435: {
436: return dwThreshold;
437: }
438:
439:
440: /*
441: *
442: * GetServerCount --
443: *
444: * Returns the number of servers in the table.
445: */
446:
447: int
448: GetServerCount( void )
449: {
450: return (int) SvrTableSz-1;
451: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.