Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!purdue!tut.cis.ohio-state.edu!cs.utexas.edu!sun-barr!ccut!titcca!kddlab!atrpost!atr-la!alain From: alain@atr-la.atr.co.jp (Alain de Cheveigne) Newsgroups: comp.sys.mac.programmer Subject: Re: ROM doesn't unlock Handles (was: ROM unlocks Handles). LONG Message-ID: <3901@atr-la.atr.co.jp> Date: 30 Dec 89 07:54:12 GMT References: <3875@atr-la.atr.co.jp> <4525@helios.ee.lbl.gov> <3888@atr-la.atr.co.jp> <9419@hoptoad.uucp> <3899@atr-la.atr.co.jp> <9433@hoptoad.uucp> Organization: ATR International,Japan Lines: 78 In article <9433@hoptoad.uucp> tim@hoptoad.uucp (Tim Maroney) writes: >In article <3899@atr-la.atr.co.jp> alain@atr-la.atr.co.jp (Alain de Cheveigne) >writes: >> /* saveBits is a Handle containing a BitMap record >> followed by the bit image data. It needs locking >> because CopyBits can move memory. */ >> >> state = HGetState((Handle) saveBits); >> HLock((Handle) saveBits); >> fixBitMap(saveBits); >> CopyBits(&(w->portBits),*saveBits, >> &(w->portRect),&(**saveBits).bounds,srcCopy,NULL); >> HSetState((Handle) saveBits, state); /* restore state */ >> >>The "contents of the block" in the quotation above would refer here to >>the BitMap record and its associated bit image data. Using the "copy >>to temp" method to avoid locking would require a big piece of stack or >>non-relocatable heap, time to copy, and the faith that whatever you >>use to copy won't scramble the heap. BlockMove() is said to be safe, >>but I'm less sure about calling strcpy() on a string in a Handle. > >A bitmap is only 14 bytes. The compiler can move it using three >MOVE.Ls and a MOVE.W. I'm pretty sure that's faster than calling a >trap -- that is, even the overhead of trap dispatch is more expensive >than that, to say nothing of what the trap does once you get to it. If you read carefully the comment that opens the code, you'll see that the Handle saveBits contains a bitmap *and* the associated bit image data, pointed to by the baseAddr field. This is much larger than 14 bytes. The purpose of the fixBitMap() routine is to make sure the baseAddr field is correct once the Handle is locked. I might have added that this code illustrates a point I tried to make earlier. Suppose that the implementation of fixBitMap() requires locking saveBits (it doesn't really, but we're supposing), and uses HLock() and HUnlock(): void fixBitMap(bitMapH) BitMap **bitMapH; { HLock(bitMapH); [do stuff] HUnlock(bitMapH); /* don't do this */ } In the calling code, saveBits remains unlocked for CopyBits(), and we die. This is an insidious bug, because the function call hides the unlocking from the calling code. This is why I advocate the use of HGetState() and HSetState(), in *all* cases where locking/unlocking is called for. You never know where your code will be called from. And I wish someone had told me when I started out programming the Mac. >>I'm less worried about WindowPtrs because they are all the same size, and >>I expect new ones to tend to occupy the slots left by old ones. > >Well, maybe and maybe not. I throw caution to the winds and go ahead >and allocate all my windows in the heap, but it's just bad design in >the MacOS that they aren't relocatable, and they *can* cause heap >fragmentation. I think WindowPtrs are the only Pointers I allocate dynamically (and DialogPtrs, but dialogs usually go away soon). I read somewhere that the Memory Manager puts pointers as far down in memory as possible. So I think that that part of the heap should consist mainly of WindowPtrs, or holes of the same size. But I haven't checked. I wonder if there's a better way. Alain de Cheveigne, alain@atr-la.atr.co.jp