[comp.sys.mac] When to HLock

tomc@mntgfx.MENTOR.COM (Tom Carstensen) (10/08/87)

Question: Do you need to HLock in the following
kind of situation?:

TEHandle TheText;
lines = (**TheText).nLines

:------------------------------------------------------------:
: Tom Carstensen              Usenet: tomc@mntgfx.MENTOR.COM :
: Mentor Graphics             GEnie:                         :
:------------------------------------------------------------:

singer@endor.harvard.edu (Richard Siegel) (10/08/87)

In article <960@mntgfx.MENTOR.COM> tomc@mntgfx.MENTOR.COM (Tom Carstensen) writes:
>Question: Do you need to HLock in the following
>kind of situation?:
>
>TEHandle TheText;
>lines = (**TheText).nLines

	No, since you're not calling a routine that might compact the heap,
you're OK. Besides, you're double-dereferencing the handle, which is
equally safe.

		--Rich

**The opinions stated herein are my own opinions and do not necessarily
represent the policies or opinions of my employer (THINK Technologies, Inc).

* Richard M. Siegel | {decvax, ucbvax, sun}!harvard!endor!singer    *
* Customer Support  | singer@endor.harvard.edu			    *
* THINK Technologies, Inc.  (No snappy quote)                       *

fry@huma1.HARVARD.EDU (David Fry) (10/08/87)

In article <960@mntgfx.MENTOR.COM> tomc@mntgfx.MENTOR.COM (Tom Carstensen) writes:
>Question: Do you need to HLock in the following
>kind of situation?:
>
>TEHandle TheText;
>lines = (**TheText).nLines

No, because you're only accessing memory and assigning it to a
stack variable, lines.  You need to HLock when memory may be
moved.  Inside Mac has a list of Toolbox calls that can move
memory, but if you don't want to look it up you can call HLock
before a Toolbox routine (better to look it up).

Suppose, however that you wanted to create a NewWindow and the
refcon was going to be the number of lines in the TEHandle,
then you must HLock before calling the NewWindow because
NewWindow may move memory:

MoveHHi(TheText);
HLock(TheText);
myWindow = NewWindow( , ,...,(**TheText).nLines );
HUnlock(TheText);

"How to Write Macintosh Software" by Scott Kastner (sp?) is
a great source for tidbits like this.

David Fry				fry@huma1.harvard.EDU
Department of Mathematics		fry@harvma1.bitnet
Harvard University			...!harvard!huma1!fry
Cambridge, MA  02138		

oster@dewey.soe.berkeley.edu (David Phillip Oster) (10/08/87)

In article <960@mntgfx.MENTOR.COM> tomc@mntgfx.MENTOR.COM (Tom Carstensen) writes:
>Question: Do you need to HLock in the following kind of situation?:

>TEHandle TheText;
>lines = (**TheText).nLines

No. Here is a simple rule:

Always lock handles if you pass a pointer to any part of the data of the
handle to a procedure or system call. Unlock them as soon as possible so
the memory manager can do a better job. Assume handles are unlocked.
Remember, resources might be purgable, and the same conditions that
cause handle data to move may also cause purgable resources to be flushed.

Here is an example:

PicHandle foo;

foo = GetResource('PICT', 128);	/* get the handle */
HLock(foo);
	 /* passing address of part of foo's contents */ 
DrawPicture(foo, &(**foo).picFrame);
HUnlock(foo);

...
/* some later use of foo */

LoadResource(foo);	/* foo is a resource. It might have been purged */

-------- versus
PicHandle foo;
Rect r;


foo = GetResource('PICT', 128);	/* get the handle */
r = (**foo).picFrame;	/* copy the frame */
HNoPurge(foo);		/* foo is a resource! */
DrawPicture(foo, &r);	/* no lock needed */
HPurge(foo);

----------

The rule above ("any procedure call or op sys call") errs on the side of
conservatism for a number of reasons:

Suppose you are calling something that you _know_ does not rearrange
the heap. You could be wrong for the following reasons:

1.) As the operating system changes, op. sys. that don't do heap
scrambles today may tomorrow.

2.) As your program grows and changes, functions you call today may do
heap scrambles tomorrow.

3.) The operating system call you may require assembly language glue,
which might be in another CODE segment. The procedure you are calling
today might get moved to another CODE segement as the program grows
and changes. Loading code segments into memory causes heap scrambles.

If you are conservative with your HLocks(), it will make your programs
run less effiecently. Extraneous Lock/UnLocks in our programs cost us
a whole 5 milliseconds every month! The alternative is La Bomba, or
days spent debugging. I know which I'd rather choose.

Pascal is particularly nasty. Pascal has these things called "Var
parameters" that are like the C "pass the address with '&'" except
there is no way for you to tell by reading a function call whether the
compiler is going to pass the address of a variable or its value.

I spoke with Bill Atkinson at the first Hacker's Conference and he
said that unlocked handles across function calls was the _costliest_
source of bugs when he was debugging MacPaint. He said that the way he
caught them was to use the DA "Monkey", which generates random key and
mouse events.  The first time he thought MacPaint was done, Monkey
crashed it in under 5 minutes. The version shipped with the first macs
had survived 2 weeks under the Monkey.  (Consumer note: If you value
your files, do not run Monkey on your hard disk.)

--- David Phillip Oster            --A Sun 3/60 makes a poor Macintosh II.
Arpa: oster@dewey.soe.berkeley.edu --A Macintosh II makes a poor Sun 3/60.
Uucp: {uwvax,decvax,ihnp4}!ucbvax!oster%dewey.soe.berkeley.edu

oster@dewey.soe.berkeley.edu (David Phillip Oster) (10/08/87)

In article <2961@husc6.UUCP> fry@huma1.UUCP (David Fry) writes:
>Suppose, however that you wanted to create a NewWindow and the
>refcon was going to be the number of lines in the TEHandle,
>then you must HLock before calling the NewWindow because
>NewWindow may move memory:

 >	MoveHHi(TheText);
 >	HLock(TheText);
 >	myWindow = NewWindow( , ,...,(**TheText).nLines );
 >	HUnlock(TheText);

Wrong. The arguments of a function are fully evaluated before the function
gets called.  (**TheText).nLines evaluates to an Integer, and integers are
passed by value in C.

Now if you had said (**TheText).lineStarts then you would have been
correct, since arrays are passed by reference in C. The address of the
lineStarts array would be computed, NewWindow would get called,
shuffle memory, and the address would be bogus by the time NewWindow
got around to using it.

mday@cgl.ucsf.edu (Mark Day) (10/09/87)

In article <21204@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) writes:
>I spoke with Bill Atkinson at the first Hacker's Conference and he
>said that unlocked handles across function calls was the _costliest_
>source of bugs when he was debugging MacPaint. He said that the way he
>caught them was to use the DA "Monkey", which generates random key and
>mouse events.  The first time he thought MacPaint was done, Monkey
>crashed it in under 5 minutes. The version shipped with the first macs
>had survived 2 weeks under the Monkey.  (Consumer note: If you value
>your files, do not run Monkey on your hard disk.)
>

I have heard of many references to this mythical Monkey DA, yet I haven't
seen it on any billboards.  Can someone give me/the net an idea where we
can get it, so we can use it to crash our programs too.
----------
		Mark Day
UUCP:		..ucbvax!ucsfcgl!mday
ARPA:		mday@cgl.ucsf.edu
BITNET:		mday@ucsfcgl.BITNET

jww@sdcsvax.UCSD.EDU (Joel West) (10/09/87)

In article <21206@ucbvax.BERKELEY.EDU>, oster@dewey.soe.berkeley.edu (David Phillip Oster) writes:
> The arguments of a function are fully evaluated before the function
> gets called.  (**TheText).nLines evaluates to an Integer, and integers are
> passed by value in C.

Of course, Pascal programs have to be careful to watch out for VAR
parameters, since VAR parameters are passed by reference and the
block might have relocated by the time the procedure call completes
and it's time to store the value.

In C, it's a little safer (one of the few times it is) since
you see the parameter being passed as &foo (by reference.)
Or rather, you hopefully saw that it was a VAR parameter and
remembered to pass it by reference (my favorite Mac C gotcha!)
-- 
	Joel West  (c/o UCSD)
	Palomar Software, Inc., P.O. Box 2635, Vista, CA  92083
	{ucbvax,ihnp4}!sdcsvax!jww 	jww@sdcsvax.ucsd.edu
So. California: where the ground does the Rocking 'N Rolling for you

bob@lznh.UUCP (<10000>Bob Lemley) (10/15/87)

In article <960@mntgfx.MENTOR.COM>, tomc@mntgfx.MENTOR.COM (Tom Carstensen) writes:
> Question: Do you need to HLock in the following
> kind of situation?:
> 
> TEHandle TheText;
> lines = (**TheText).nLines

Answer: No, but be sure to allocate memory space for the TextEdit record
via TENew() before accessing any fields of the TE record.

Usually, you lock handles down only if you are both:
	1) dereferencing the handle
	AND
	2) making a call to a routine which may purge or move memory.

For example, if you passed the address of an ELEMENT
contained in an unlocked heap structure to a subroutine and
the subroutine made a toolbox call that moved memory,
the pointer you passed could become invalid
(ie. point to garbage, or worse, to important system data).

Usually, you should call MoveHHi after locking a handle to avoid
heap fragmentation problems.

Inside Mac contains an appendix of all ToolBox and OS routines which
might purge or move memory.

Robert C. Lemley    { ihnp4 | allegra } lznh!bob

bob@lznh.UUCP (<10000>Bob Lemley) (10/15/87)

> In article <2961@husc6.UUCP>, fry@huma1.HARVARD.EDU (David Fry) writes:
>> In article <960@mntgfx.MENTOR.COM> tomc@mntgfx.MENTOR.COM (Tom Carstensen) writes:
> >Question: Do you need to HLock in the following
	[ excess removed ]
> MoveHHi(TheText);
> HLock(TheText);
> myWindow = NewWindow( , ,...,(**TheText).nLines );
> HUnlock(TheText);

HLock is not required here because the dereferencing is done BEFORE
the JSR to NewWindow.