Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!purdue!tut.cis.ohio-state.edu!ucbvax!dewey.soe.berkeley.edu!oster From: oster@dewey.soe.berkeley.edu (David Phillip Oster) Newsgroups: comp.sys.mac.programmer Subject: Re: Segmentation (was Re: ARRGH (Strings and things)) Message-ID: <32323@ucbvax.BERKELEY.EDU> Date: 2 Nov 89 07:44:39 GMT References: <16004@netnews.upenn.edu> <8835@hoptoad.uucp> <16420@dartvax.Dartmouth.EDU> <8852@hoptoad.uucp> <14386@well.UUCP> <8878@hoptoad.uucp> <1989Nov2.053139.23967@agate.berkeley.edu> Sender: usenet@ucbvax.BERKELEY.EDU Reply-To: oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) Organization: School of Education, UC-Berkeley Lines: 69 I recently HAD to use UnloadSeg(). The marketing manager called me on one of the products I was writing and said, "Help, the program is now so big it will only allow 2400 records on a 1Meg MacPlus. The box says 2600. It will take six weeks to make new boxes and we need to ship NOW!" So, I had to use unloadseg to get space when the user's files got large. Here is the big problem: There MUST be space to load a required segment. If the o.s. can't find space, it will crash. You are making an innocent, arbitrary procedure call, and _kaboom_. Hard to debug and hard to fix. Some work arounds: 1.) you can do a setjump in your main loop, and a longjump in your growzone routine. This should sort of work. Note though, your growzone function is called whenever anything needs memory including the o.s. doing a longjump from inside the o.s. is a good way to leave it in an inconstant state. For your own code, you can use Signal (see the tech notes,) and declare a cleanup routine that will get executed during the longjump, but it isn't easy to retrofit this kind of thing into an almost done 40,000 line program. 2.) your development system will let you find out what segment (by number) each procedure is in. You can add a few: if(NIL == GetResource('CODE', MAINDOCUPDATESEGNUM)){ Error(IAMSORRYDAVE); } that is, the program makes a probe to see if it will be able to get the segment it needs to do a command. If it can't the user sees an error message. (This assumes the error message code is in the main segment.) This is technique I used. My programs are object oriented, so my message dispatcher can return the error code MESSAGEUNDELIVERABLENOTATHOME, if I sen d a message to an object whose code can not be read. This has some problems: I have to manage my own symbols for my segments, which might get out of date as I rearrange my procedures. I wish there were a system call: CanLoadSeg(procedureName) which returns NIL or a handle to the segment. It always bothers me when I see a function with an obvious inverse that is not implemented. (Yes, I know I could write it, but would it work in System 7?) My next program will use technique 1, unless you good folk can tell me a better way to do things. I usually only unload segments in my main loop, but occasionally, when I need extra room (for example during a Save or a spool Print.) I call a procedure that unlocks all purgable segments except 1: the save segment for save or the print segment for Print. This issue is only a small part of the larger issue of memory management in Mac programs: for example: should your grow zone function throw away undo information as a last ditch attempt to make extra room? How about if you need the room while in the middle of executing a ReDo command? The simple answer is: don't print "max sizes handled" on your boxes. Have your program enforce conservative limits on the user. Maybe I'm just taking "the power to be your best" too much to heart. You may have noticed that I answer more questions than I ask. Am I trying too hard on this issue? > The mac is a detour in the inevitable march of mediocre computers. > drs@bnlux0.bnl.gov (David R. Stampf) --- David Phillip Oster -master of the ad hoc odd hack. Arpa: oster@dewey.soe.berkeley.edu Uucp: {uwvax,decvax}!ucbvax!oster%dewey.soe.berkeley.edu Summary/Conclusion: if your mac program calls a procedure in a segment that isn't loaded, the segment loader will call LoadSeg() to fetch it. If LoadSeg() fails, the mac crashes. This can bite you even if you never call UnloadSeg() since a segment only gets loaded when you call it for the first time (which might be AFTER you read a giant file.)