|
|
1.1 root 1: /************************************************************************
2: *
3: * lfthread.c -- Subroutines for thread management for LineFractal.
4: *
5: * Created by Microsoft Corporation, 1989
6: *
7: ************************************************************************/
8:
9: #define INCL_WIN
10: #define INCL_GPI
11: #define INCL_DOSSEMAPHORES
12: #define INCL_DOSMEMMGR
13: #define INCL_DOSPROCESS
14: #define INCL_DOSERRORS
15: #include <os2.h>
16:
17: #include <mt\process.h>
18: #include <mt\stddef.h>
19:
20: #define INCL_GLOBALS
21: #define INCL_THREADS
22: #include "linefrac.h"
23:
24: #define INCL_LFCMD
25: #define INCL_LFMAIN
26: #define INCL_LFPS
27: #define INCL_LFUTIL
28: #define INCL_LFTHREAD
29: #define INCL_LFDRAW
30: #include "lffuncs.h"
31:
32:
33:
34:
35: /************************************************************************
36: *
37: * Global Variables
38: *
39: ************************************************************************/
40:
41: extern GLOBALDATA global;
42:
43:
44:
45:
46: /************************************************************************
47: *
48: * LfStartThread
49: *
50: * Do everything needed to start up a background thread drawing
51: * fractals.
52: *
53: * This includes:
54: *
55: * Allocate space for thread structure.
56: * Initialize fields of thread structure.
57: * Create a presentation space for the thread.
58: * Create stack space for the thread.
59: * Set the thread's semaphore to block -- i.e. don't start
60: * drawing until everything is ready.
61: * Start the thread.
62: * Set the thread's priority to idle time.
63: *
64: ************************************************************************/
65:
66: #define SIZE_ACCUM_STACK 2048
67:
68: PTHR
69: LfStartThread(dcType)
70: USHORT dcType;
71: {
72: PTHR pthr;
73:
74:
75: pthr = NULL; /* zero out all 32 bits */
76: if (DosAllocSeg(sizeof(THR), ((PUSHORT)&pthr)+1, 0))
77: return NULL;
78:
79: pthr->dcType = dcType;
80:
81: LfPreInitThread(pthr);
82: if (LfCreatePS(pthr))
83: {
84: LfPostInitThread(pthr);
85: if (DosAllocSeg(SIZE_ACCUM_STACK, &pthr->selStack, 0))
86: goto lfst_exit;
87:
88: DosSemSet(&pthr->lSemRedraw);
89: pthr->tid = _beginthread(LineFractalThread, MAKEP(pthr->selStack, 0), SIZE_ACCUM_STACK, pthr);
90: if (pthr->tid == -1)
91: {
92: LfDeletePS(pthr);
93: goto lfst_exit;
94: }
95: DosSetPrty(PRTYS_THREAD, PRTYC_IDLETIME, 0, pthr->tid);
96:
97: LfSelectXform(global.hwnd, pthr, pthr->usCurXform);
98: DosSemClear(&pthr->lSemRedraw);
99:
100: if (!DevQueryCaps(pthr->hdc, CAPS_HORIZONTAL_RESOLUTION, 2L, (PLONG)&(pthr->AspectRatio)))
101: {
102: pthr->AspectRatio.lHorz = 1L;
103: pthr->AspectRatio.lVert = 1L;
104: }
105:
106: return pthr;
107: }
108: lfst_exit:
109: DosFreeSeg(*(((PUSHORT)&pthr)+1));
110: return NULL;
111: }
112:
113:
114:
115:
116: /************************************************************************
117: *
118: * LfPreInitThread
119: *
120: * Initialize constant values in the thread structure needed from
121: * the moment the thread starts. If thread inheritance is enabled,
122: * then copy as much as possible from the top thread, if there is
123: * one.
124: *
125: ************************************************************************/
126:
127: VOID
128: LfPreInitThread(pthr)
129: PTHR pthr;
130: {
131: pthr->hps = NULL;
132: pthr->hdc = NULL;
133: pthr->hbm = NULL;
134: pthr->fTimeToDie = FALSE;
135: pthr->fUpdateAttrs = FALSE;
136: pthr->fBusy = FALSE;
137: pthr->pptl = NULL;
138: pthr->cptl = 0;
139: pthr->pmatlf = NULL;
140:
141: if (global.fThreadInheritance && global.pThrTop)
142: {
143: pthr->cPlanes = global.pThrTop->cPlanes ;
144: pthr->cBitCount = global.pThrTop->cBitCount ;
145:
146: pthr->cxWCS = global.pThrTop->cxWCS ;
147: pthr->cyWCS = global.pThrTop->cyWCS ;
148:
149: pthr->fAutoSizePS = global.pThrTop->fAutoSizePS ;
150: pthr->fAutoSelectDims = global.pThrTop->fAutoSelectDims ;
151: pthr->fClearOnRedraw = global.pThrTop->fClearOnRedraw ;
152: pthr->fAutoStartRedraw = global.pThrTop->fAutoStartRedraw ;
153: pthr->fCollectBounds = global.pThrTop->fCollectBounds ;
154:
155: pthr->fFracRedraw = global.pThrTop->fFracRedraw ;
156: pthr->fPrimRedraw = global.pThrTop->fPrimRedraw ;
157: pthr->fAttrRedraw = global.pThrTop->fAttrRedraw ;
158:
159: pthr->lb = global.pThrTop->lb ;
160: pthr->flLineAttrs = LFA_LINEALL ;
161: pthr->mb = global.pThrTop->mb ;
162: pthr->flMarkerAttrs = LFA_MARKALL ;
163: pthr->ab = global.pThrTop->ab ;
164: pthr->flAreaAttrs = LFA_AREAALL ;
165: pthr->ib = global.pThrTop->ib ;
166: pthr->flImageAttrs = LFA_IMAGEALL ;
167:
168: pthr->usCurPrim = global.pThrTop->usCurPrim ;
169: pthr->usCurXform = global.pThrTop->usCurXform ;
170: pthr->usRecursion = global.pThrTop->usRecursion ;
171: pthr->usPolygonSides = global.pThrTop->usPolygonSides ;
172: pthr->cptMax = global.pThrTop->cptMax ;
173: pthr->dblXOff = global.pThrTop->dblXOff ;
174: pthr->dblYOff = global.pThrTop->dblYOff ;
175: pthr->dblXScale = global.pThrTop->dblXScale ;
176: pthr->dblYScale = global.pThrTop->dblYScale ;
177: pthr->dblRotation = global.pThrTop->dblRotation ;
178: pthr->flMiscAttrs = LFA_MISCALL ;
179: }
180: else
181: {
182: pthr->cPlanes = global.bm.cPlanes;
183: pthr->cBitCount = global.bm.cBitCount;
184:
185: pthr->cxWCS = 10000L;
186: pthr->cyWCS = 10000L;
187:
188: pthr->fAutoSizePS = TRUE;
189: pthr->fAutoSelectDims = TRUE;
190: pthr->fClearOnRedraw = TRUE;
191: pthr->fAutoStartRedraw = FALSE;
192: pthr->fCollectBounds = TRUE;
193:
194: pthr->fFracRedraw = TRUE;
195: pthr->fPrimRedraw = TRUE;
196: pthr->fAttrRedraw = TRUE;
197:
198: pthr->lb.lColor = CLR_NEUTRAL;
199: pthr->lb.usMixMode = FM_OVERPAINT;
200: pthr->lb.fxWidth = LINEWIDTH_NORMAL;
201: ; pthr->lb.lGeomWidth = 1L;
202: pthr->lb.usType = LINETYPE_SOLID;
203: ; pthr->lb.usEnd = LINEEND_FLAT;
204: ; pthr->lb.usJoin = LINEJOIN_BEVEL;
205: pthr->flLineAttrs = LFA_LINEALL;
206:
207: pthr->mb.lColor = CLR_NEUTRAL;
208: pthr->mb.lBackColor = CLR_BACKGROUND;
209: pthr->mb.usMixMode = FM_OVERPAINT;
210: pthr->mb.usBackMixMode = BM_LEAVEALONE;
211: pthr->mb.usSet = LCID_DEFAULT;
212: pthr->mb.usSymbol = MARKSYM_DIAMOND;
213: ; pthr->mb.sizfxCell.cx = 0L;
214: ; pthr->mb.sizfxCell.cy = 0L;
215: pthr->flMarkerAttrs = LFA_MARKALL;
216:
217: pthr->ab.lColor = CLR_NEUTRAL;
218: pthr->ab.lBackColor = CLR_BACKGROUND;
219: pthr->ab.usMixMode = FM_OVERPAINT;
220: pthr->ab.usBackMixMode = BM_OVERPAINT;
221: pthr->ab.usSet = LCID_DEFAULT;
222: pthr->ab.usSymbol = PATSYM_NOSHADE;
223: ; pthr->ab.ptlRefPoint.x = 0L;
224: ; pthr->ab.ptlRefPoint.y = 0L;
225: pthr->flAreaAttrs = LFA_AREAALL;
226:
227: pthr->ib.lColor = CLR_NEUTRAL;
228: pthr->ib.lBackColor = CLR_BACKGROUND;
229: pthr->ib.usMixMode = FM_OVERPAINT;
230: pthr->ib.usBackMixMode = FM_OVERPAINT;
231: pthr->flImageAttrs = LFA_IMAGEALL;
232:
233: pthr->usCurPrim = IDM_POLYLINE;
234: pthr->usCurXform = IDM_SAWTOOTH;
235: pthr->usRecursion = 1;
236: pthr->usPolygonSides = 3;
237: pthr->cptMax = MAX_POINT_COUNT;
238: pthr->dblXOff = 0.125;
239: pthr->dblYOff = 0.5;
240: pthr->dblXScale = 0.75;
241: pthr->dblYScale = 0.75;
242: pthr->dblRotation = 0.0;
243: pthr->flMiscAttrs = LFA_MISCALL;
244: }
245:
246: }
247:
248:
249:
250:
251: /************************************************************************
252: *
253: * LfPostInitThread
254: *
255: * Initialize various values in the thread structure which required
256: * that a PS/DC/BM had been created. If thread inheritance is enabled,
257: * then copy as much as possible from the top thread, if there is
258: * one.
259: *
260: ************************************************************************/
261:
262: VOID
263: LfPostInitThread(pthr)
264: PTHR pthr;
265: {
266: if (!(global.fThreadInheritance && global.pThrTop))
267: {
268: pthr->lb.lGeomWidth = GpiQueryLineWidthGeom(pthr->hps);
269: pthr->lb.usEnd = (USHORT) GpiQueryLineEnd(pthr->hps);
270: pthr->lb.usJoin = (USHORT) GpiQueryLineJoin(pthr->hps);
271:
272: DevQueryCaps(pthr->hdc, CAPS_MARKER_WIDTH, 1L, (PLONG)&(pthr->mb.sizfxCell.cx));
273: DevQueryCaps(pthr->hdc, CAPS_MARKER_HEIGHT, 1L, (PLONG)&(pthr->mb.sizfxCell.cy));
274:
275: GpiQueryPatternRefPoint(pthr->hps,&(pthr->ab.ptlRefPoint));
276: }
277: }
278:
279:
280:
281:
282: /************************************************************************
283: *
284: * LfKillThread
285: *
286: * Force the given thread to die and release its resources.
287: *
288: ************************************************************************/
289:
290: VOID
291: LfKillThread(pthr)
292: PTHR pthr;
293: {
294: int i, j;
295:
296:
297: /* This does not do anything if there aren't any threads. */
298:
299: if (global.cThr && pthr)
300: {
301: /****************************************************************
302: * Tell the thread to die when it can.
303: * If blocked on lSemRedraw, then it will recognize fTimeToDie
304: * as soon as it's unblocked. If it's currently drawing,
305: * it will recognize fInterrupted, kick out of the recursion,
306: * loop back up to check lSemRedraw, which will be clear, so
307: * it'll do as already mentioned. Set the priority to time-
308: * critical to speed things up.
309: ****************************************************************/
310:
311: pthr->fTimeToDie = TRUE;
312: pthr->fInterrupted = TRUE;
313: DosSetPrty(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, pthr->tid);
314: DosSemClear(&pthr->lSemRedraw);
315:
316:
317: /****************************************************************
318: * Once it's decided it must die, it will clean up after
319: * itself and exit quietly. To detect when it has actually
320: * exited, so that we can safely free up the stack, we will
321: * loop asking for the thread's priority until an error occurs.
322: * We will assume that an error implies the thread has exited.
323: ****************************************************************/
324:
325: {
326: USHORT usT;
327: USHORT usRet;
328: while (!(usRet = DosGetPrty(PRTYS_THREAD, &usT, pthr->tid)));
329: if (usRet != ERROR_INVALID_THREADID)
330: {
331: MyMessageBox(global.hwnd,
332: "Cannot kill thread");
333: return;
334: }
335: }
336:
337:
338: /****************************************************************
339: * Extract the given thread from the group. This is done
340: * inside a critical section because the drawing threads
341: * call LfIsThreadTop, which reads global.aThr.
342: ****************************************************************/
343:
344: i = 0;
345: while ((i < global.cThr) && (pthr != global.aThr[i]))
346: ++i; /* if i == global.cThr we have a problem */
347: DosEnterCritSec();
348: for (j = i; j < global.cThr-1; ++j)
349: global.aThr[j] = global.aThr[j+1];
350: global.aThr[j] = NULL; /* clear out all copies of pthr */
351: --global.cThr;
352: DosExitCritSec();
353:
354:
355: /****************************************************************
356: * Free up resources allocated for the thread.
357: ****************************************************************/
358:
359: LfDeletePS(pthr);
360: DosFreeSeg(pthr->selStack);
361: DosFreeSeg(*(((PUSHORT)&pthr)+1));
362: }
363: }
364:
365:
366:
367:
368: /************************************************************************
369: *
370: * LfBringThreadToTop
371: *
372: * Bring the specified thread to the top, and invalidate the window
373: * to force a WM_PAINT message to make the thread's image visible.
374: * The given thread can be NULL, in which case just set pThrTop to
375: * NULL.
376: *
377: ************************************************************************/
378:
379: VOID
380: LfBringThreadToTop(pthr)
381: PTHR pthr;
382: {
383: int i;
384:
385:
386: /********************************************************************
387: * Find the given thread in the group.
388: ********************************************************************/
389:
390: if (pthr)
391: {
392: i = 0;
393: while ((i < global.cThr) && (pthr != global.aThr[i]))
394: ++i; /* if i == global.cThr, we have problems */
395: }
396: else
397: i = 32767; /* should cause gp fault if used */
398:
399:
400: /********************************************************************
401: * If the user wants the menu items updated, and we're switching
402: * away from an active thread, then uncheck the current thread's
403: * settings.
404: ********************************************************************/
405:
406: if (global.fUpdateMenusOnThreadSwitch)
407: {
408: if (global.pThrTop)
409: {
410: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_AUTORESIZE);
411: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_AUTOSELECTDIMS);
412: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_CLEARONREDRAW);
413: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_AUTOSTARTREDRAW);
414: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_COLLECTBOUNDS);
415: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_FRACREDRAW);
416: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_PRIMREDRAW);
417: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_ATTRREDRAW);
418: UNCHECK_MENU_ITEM(global.hwndFrame, global.pThrTop->usCurPrim);
419: UNCHECK_MENU_ITEM(global.hwndFrame, global.pThrTop->usCurXform);
420: UNCHECK_MENU_ITEM(global.hwndFrame, global.pThrTop->dcType);
421: }
422: }
423:
424:
425: /********************************************************************
426: * Switch the given thread to the top.
427: ********************************************************************/
428:
429: DosEnterCritSec();
430: global.iThrTop = i;
431: global.pThrTop = pthr;
432: DosExitCritSec();
433:
434:
435: /********************************************************************
436: * If we switched in a living thread, then invalidate the entire
437: * window. This will cause a WM_PAINT message to be sent, which
438: * will display the image from the new top thread. If the user
439: * has not disabled updating of the menus, then do that.
440: ********************************************************************/
441:
442: if (pthr)
443: {
444: WinInvalidateRect(global.hwnd, NULL, FALSE);
445:
446: /* If the user wants menu items updated, then do it now. */
447: if (global.fUpdateMenusOnThreadSwitch)
448: {
449: TOGGLE_MENU_ITEM(global.hwndFrame, IDM_AUTORESIZE, pthr->fAutoSizePS);
450: TOGGLE_MENU_ITEM(global.hwndFrame, IDM_AUTOSELECTDIMS, pthr->fAutoSelectDims);
451: TOGGLE_MENU_ITEM(global.hwndFrame, IDM_CLEARONREDRAW, pthr->fClearOnRedraw);
452: TOGGLE_MENU_ITEM(global.hwndFrame, IDM_AUTOSTARTREDRAW, pthr->fAutoStartRedraw);
453: TOGGLE_MENU_ITEM(global.hwndFrame, IDM_COLLECTBOUNDS, pthr->fCollectBounds);
454: TOGGLE_MENU_ITEM(global.hwndFrame, IDM_FRACREDRAW, pthr->fFracRedraw);
455: TOGGLE_MENU_ITEM(global.hwndFrame, IDM_PRIMREDRAW, pthr->fPrimRedraw);
456: TOGGLE_MENU_ITEM(global.hwndFrame, IDM_ATTRREDRAW, pthr->fAttrRedraw);
457: CHECK_MENU_ITEM (global.hwndFrame, pthr->usCurPrim);
458: CHECK_MENU_ITEM (global.hwndFrame, pthr->usCurXform);
459: CHECK_MENU_ITEM (global.hwndFrame, pthr->dcType);
460:
461: LfUpdateThreadMenu();
462: }
463: }
464: }
465:
466:
467:
468:
469: /************************************************************************
470: *
471: * LfIsThreadTop
472: *
473: * Returns TRUE if the given thread is the top one. Putting this
474: * test in a function isolates it and makes it easier to maintain
475: * a critical section.
476: *
477: ************************************************************************/
478:
479: BOOL
480: LfIsThreadTop(pthr)
481: PTHR pthr;
482: {
483: BOOL f;
484:
485: f = FALSE;
486: DosEnterCritSec();
487: if (pthr == global.pThrTop)
488: f = TRUE;
489: DosExitCritSec();
490:
491: return f;
492: }
493:
494:
495:
496:
497: /************************************************************************
498: *
499: * LfUpdateThreadMenu
500: *
501: * Brings the "Thread Bring thread to top" submenu in line with the
502: * currently active threads.
503: *
504: ************************************************************************/
505:
506: VOID
507: LfUpdateThreadMenu()
508: {
509: /*
510: * Enable the numbers for threads that do exist.
511: * Disable the numbers for threads that don't exist.
512: * Uncheck everything, then check the right one.
513: */
514:
515: int i;
516:
517: for (i = 0; i < global.cThr; ++i)
518: {
519: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_THR0TOTOP+i);
520: ENABLE_MENU_ITEM (global.hwndFrame, IDM_THR0TOTOP+i);
521: }
522:
523: for ( ; i < MAX_THREADS; ++i)
524: {
525: UNCHECK_MENU_ITEM(global.hwndFrame, IDM_THR0TOTOP+i);
526: DISABLE_MENU_ITEM(global.hwndFrame, IDM_THR0TOTOP+i);
527: }
528:
529: CHECK_MENU_ITEM(global.hwndFrame, IDM_THR0TOTOP + global.iThrTop);
530: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.