oster@dewey.soe.berkeley.edu (David Phillip Oster) (12/04/89)
In article <3838@atr-la.atr.co.jp> alain@atr-la.atr.co.jp (Alain de Cheveigne) writes:
_>If you use HGetState and HSetState instead, the routine leaves all handles
_>just the way they were before the routine was called. The caller doesn't
_>have to know how the callee does his stuff, which is the way it should be.
_>But it seems that some ROM routines don't know it, and unlock handles
_>behind one's back. A list of those would be nice.
Alain, you have to understand "The Way od the Macintosh." The ROM
expects you to only lock down what you absolutely have to, and that for as
short a time as possible. To do otherwise is to risk running out of
usable memory because of fragmentation. if you use a style like:
HLock(handle);
OneSystemCall();
HUnlock(handle);
or even better:
temp = (**hand).field;
SystemCall(&temp);
(**hand).field = temp;
you'll never have to worry about the ROM unlocking things.
alain@atr-la.atr.co.jp (Alain de Cheveigne) (12/05/89)
In article <32977@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu (David Phillip Oster) writes: >In article <3838@atr-la.atr.co.jp> alain@atr-la.atr.co.jp (Alain de Cheveigne) writes: >>If you use HGetState and HSetState instead, the routine leaves all handles >>just the way they were before the routine was called. The caller doesn't >>have to know how the callee does his stuff, which is the way it should be. >> >>But it seems that some ROM routines don't know it, and unlock handles >>behind one's back. A list of those would be nice. > >Alain, you have to understand "The Way od the Macintosh." The ROM >expects you to only lock down what you absolutely have to, and that for as >short a time as possible. To do otherwise is to risk running out of >usable memory because of fragmentation. I agree. I'm assuming that the duration of my (short) subroutine is a short time. Granted, this assumption might be wrong if memory is tight and some is needed during the subroutine. But if I move the handles up in the heap before locking them, it is unlikely they will get in the way of heap compaction, because the subroutine is not likely to free any space above them. >If you use a style like: > HLock(handle); > OneSystemCall(); > HUnlock(handle); >or even better: > temp = (**hand).field; > SystemCall(&temp); > (**hand).field = temp; >you'll never have to worry about the ROM unlocking things. I run into two problems with these schemes: a) The structures I use are deep. Concretely: my program uses lots of windows, which the user can create and dispose of in any order. Data is attached to each window in a relocable block, referred to by the window refCon, and that block in turn refers to other relocatable data and to another window (itself with data). So reference to a given field is done through many levels of indirection, most of them relocatable... I can't imagine locking and unlocking all this stuff at every system call, so this rules out the first scheme. b) Several of my data fields are big: text, signal arrays, and bit images used by bitmaps (yes, I'm aware of the dangers of relocating these...). I don't want to copy the data each time it is used in a system call. Or should I...? It took me lots of fumbling before I found a way to cope with handle-locking in a reasonably clean way (that can survive program modification, for example...). But I can't say it satisfies me. If someone can point a better way, please do. To make things clear, my present strategy is: a) On entry of a subroutine, save states of all handles that might be dereferenced, b)MoveHHi() and HLock() them, c) do the processing, and d) Restore handle states on exit (rather than unlock). State saving/locking and restoring is done either handle by handle, or on a window scale: a single routine locks all the data structures associated with the window, after saving their state in a state vector that is it returns. Another routine restores the states on exit. Once the structures are locked, data fields are accessed through a battery of macros that take the window as argument. No need for locking and unlocking, *except* after some system calls that unlock their argument as a side effect (the subject of my original posting). What justifies the hassle is this: I can now forget the insides of a subroutine. If I call it in some code, I don't have to remember to re-lock or unlock every handle that it might have twiddled internally (possibly as a side effect of another routine it called...). If I modify a subroutine, I don't have to go around checking for side effects. But hassle it is. Is there a better way ? Alain de Cheveigne, alain@atr-la.atr.co.jp
oster@dewey.soe.berkeley.edu (David Phillip Oster) (12/06/89)
In article <3842@atr-la.atr.co.jp> alain@atr-la.atr.co.jp (Alain de Cheveigne) writes: >But hassle it is. Is there a better way ? Yes. What complexity, and slowness! (all those unnecessary MovHHi()s can really slow a program down.) I too use very similar data structrues: handles in the RefCons of my windows that themselves reference other handles. If a field referenced by an O.S. call is small, copy it. If it is large, lock the owning handle during the call. Do not write your own routines to take pointers into handles, instead, if you must do such a thing, do it by passing a handle an an offset. (Often you can just pass the handle, since the routine knows its offset.) Here is an example, from a program that uses a window handle which references two pixmaps. (I keep the current window handle in a global variable called "theDoc", by analogy with "thePort".) Notice, no need for any HLocks or MoveHHis. /* DocDispose - discard our window */ DocDispose(){ if(NIL != (**theDoc).newPix){ if(NIL != (**(**theDoc).newPix).baseAddr){ DisposPtr((**(**theDoc).newPix).baseAddr); (**(**theDoc).newPix).baseAddr = NIL; } DisposPixMap((**theDoc).newPix); } if(NIL != (**theDoc).oldPix){ if(NIL != (**(**theDoc).oldPix).baseAddr){ DisposPtr((**(**theDoc).oldPix).baseAddr); (**(**theDoc).oldPix).baseAddr = NIL; } DisposPixMap((**theDoc).oldPix); } DisposHandle((Handle) theDoc); DisposeWindow(thePort); } Actually, this does bring up a question. Inside Mac Vol 5 doesn't say precisely which fields are disposed when you call DisposPixMap(). --- According to the Constitution, the Constitution is unconstitutional: --- David Phillip Oster --U.S.Constitution I.10.1: "No State shall Arpa: oster@dewey.soe.berkeley.edu --enter into any treaty, alliance, or Uucp: {uwvax,decvax}!ucbvax!oster%dewey.soe.berkeley.edu -- confederation..."
lippin@ronzoni.berkeley.edu (The Apathist) (12/06/89)
Recently alain@atr-la.atr.co.jp (Alain de Cheveigne) wrote: >In article <32977@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu >(David Phillip Oster) writes: [Good stuff deleted] >>If you use a style like: >> HLock(handle); >> OneSystemCall(); >> HUnlock(handle); >>or even better: >> temp = (**hand).field; >> SystemCall(&temp); >> (**hand).field = temp; >>you'll never have to worry about the ROM unlocking things. >I run into two problems with these schemes: > >a) The structures I use are deep. Concretely: my program uses lots of >windows, which the user can create and dispose of in any order. Data >is attached to each window in a relocable block, referred to by the >window refCon, and that block in turn refers to other relocatable data >and to another window (itself with data). So reference to a given >field is done through many levels of indirection, most of them >relocatable... I can't imagine locking and unlocking all this stuff >at every system call, so this rules out the first scheme. > >b) Several of my data fields are big: text, signal arrays, and bit >images used by bitmaps (yes, I'm aware of the dangers of relocating >these...). I don't want to copy the data each time it is used in a >system call. Most of the VAR-parameters the system wants are no larger than a long word. If these are located in relocatable blocks, I recommend using a shadow variable on the stack for the call. In the case of larger parameters by reference, I recommend locking the block first, and restoring its restoring its state afterward. HGetState/HSetState is sometimes better, but most handles are only locked only in extreme circumstances, and HUnlock will suffice for them. Note that only the block containing the parameter needs to be locked; "parent" blocks are free to slide around. The other reason for locking a handle is so that you may carry around a dereference to it. In general, I avoid passing such a handle to any major subroutine, be it my own or part of the operating system. With the obvious exceptions, I never pass a locked handle to the OS. When it becomes necessary to do so, I usually will unlock the block for the duration of the call and recompute the dereference afterward. Or consider getting rid of the dereference entirely. These rules won't cover every instance, but I find that the exceptions are few and far between. Finally, a note on MoveHHi -- this call is easy to overuse. It's only an advantage if a block is going to remain locked for a respectable length of time; in particular, only when there's a chance of significant memory allocation while the block is locked. If used when not necessary, it wastes time with frivolous heap shuffling. Since I avoid keeping handles locked for such periods, I use MoveHHi very sparingly. --Tom Lippincott lippin@math.berkeley.edu "It's a poor sort of memory that only works backwards." --The Red Queen
shebanow@Apple.COM (Andrew Shebanow) (12/07/89)
In article <32977@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) writes: >Alain, you have to understand "The Way od the Macintosh." The ROM >expects you to only lock down what you absolutely have to, and that for as >short a time as possible. To do otherwise is to risk running out of >usable memory because of fragmentation. if you use a style like: > HLock(handle); > OneSystemCall(); > HUnlock(handle); >or even better: > temp = (**hand).field; > SystemCall(&temp); > (**hand).field = temp; >you'll never have to worry about the ROM unlocking things. Ack! Please, please don't do this! If the system call expects a Handle, you should never, ever pass it a fake handle. While your technique will work on current Mac System Software, it will break under System 7.0 if you are running in 32 Bit Mode. The new Memory Manager doesn't store the handle flags in the high byte of the Master Ptr anymore, so you will end up trashing your memory. As far as it goes, there is (should be) very little code left in the system which goes around unlocking things on you. Almost everything has been fixed to use HGetState/HSetState. For more info on this subject, see Tech Note 212 on 32 Bit Cleanliness. Andrew Shebanow MacDTS
lim@iris.ucdavis.edu (Lloyd Lim) (12/07/89)
In article <5640@internal.Apple.COM> shebanow@Apple.COM (Andrew Shebanow) writes: >In article <32977@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) writes: >>[...] >> temp = (**hand).field; >> SystemCall(&temp); >> (**hand).field = temp; >>[...] > >Ack! Please, please don't do this! If the system call expects a >Handle, you should never, ever pass it a fake handle. While your >technique will work on current Mac System Software, it will break >[...] >Andrew Shebanow >MacDTS Ack! Fake handle? What, where? The SystemCall just wants a pointer to a variable (Pascal VAR parameter). Copying a field into a local temporary is a perfectly valid way of eliminating moving memory problems. There are no fake handles here. Please read a little more carefully. DTS has not looked good lately with the recent tech note errors and flame war postings. +++ Lloyd Lim Internet: lim@iris.ucdavis.edu (128.120.57.20) Compuserve: 72647,660 US Mail: 146 Lysle Leach Hall, U.C. Davis, Davis, CA 95616
shebanow@Apple.COM (Andrew Shebanow) (12/07/89)
OK, I admit I overreacted. The technique David is using is generally safe, but I thought that the way is was stated, it looked like there was a potential problem with the code. However, this problem would only occur if a dereferenced handle is stored in the structure, which was the case I (mistakenly) thought he was showing. I apologize to David for accusing him of fake-handlism. As for DTS's image on the net, all I can say is that I hope that people have enough sense to keep the writings of individual DTS people seperate in their heads. We don't speak on UseNet as part of our job: it is just something that we (collectively) do to encourage the spreading of information, on our own time. Personally, I don't want to be lumped into any group for my postings. What I write, I write, and I want neither credit nor scorn for what Paul, Keith, or any other DTS/Apple people choose to write. Andy Shebanow MacDTS
siegel@endor.harvard.edu (Rich Siegel) (12/08/89)
In article <5640@internal.Apple.COM> shebanow@Apple.COM (Andrew Shebanow) writes: >> temp = (**hand).field; >> SystemCall(&temp); >> (**hand).field = temp; > >Ack! Please, please don't do this! If the system call expects a >Handle, you should never, ever pass it a fake handle. While your That's not a fake handle; it's a copy of a field of a handled block. David made no assertions about the system call's parameters; in this particular case, it looks like the system call takes some other type of argument, but may move memory. In principle, you are correct, though. Fake handles are not a good thing. R. ~~~~~~~~~~~~~~~ Rich Siegel Staff Software Developer Symantec Corporation, Language Products Group Internet: siegel@endor.harvard.edu UUCP: ..harvard!endor!siegel "There is no personal problem which cannot be solved by sufficient application of high explosives." ~~~~~~~~~~~~~~~