[comp.windows.ms.programmer] Windows 3 segment/selector problems

ge@phoibos.cs.kun.nl (Ge Weijers) (12/19/90)

I'm about to begin writing a largish programming language implementation
to run under Windows-3 in standard and 386 enhanced mode. The language,
Scheme, needs a garbage-collected heap. My problem is:

Do selector numbers refering to blocks of memory change through the lifetime of
a program? If they do I have to address all memory through a special table,
which would slow down the implementation severely. Does the alternative,
keeping the heap blocks locked for all time, give major problems?
The documentation (SDK) is not very specific on this.

Any info appreciated.

Ge' Weijers

Ge' Weijers                                    Internet/UUCP: ge@cs.kun.nl
Faculty of Mathematics and Computer Science,   (uunet.uu.net!cs.kun.nl!ge)
University of Nijmegen, Toernooiveld 1         tel. +3180612483 (UTC+1,
6525 ED Nijmegen, the Netherlands               UTC+2 march/september

nickel@cs.utexas.edu (Jody P. Nickel) (12/19/90)

If you are only going to run in 386 enhanced mode the this will simplify
your task immensely. After a GlobalAlloc, you can lock this memory and
leave it locked until it is no longer needed. The far pointer you receive
is a selector:0 pointer. The selector is valid as long as the memory stays
allocted. i.e. Don't free the memory and expect the pointer to be valid. 
The indirection from the selector to the physical address is handled by
the 386. This indirection is very fast, but the loading of a new selector
into a segment register is expensive, minimize the number of times you 
load a segment register and your performance should be acceptable.

mojo@netcom.UUCP (Morris Jones) (12/20/90)

ge@cs.kun.nl writes:
>Do selector numbers refering to blocks of memory change through the lifetime of
>a program? If they do I have to address all memory through a special table,
>which would slow down the implementation severely. Does the alternative,
>keeping the heap blocks locked for all time, give major problems?

In enhanced mode, memory selectors don't change.  If you really must, you
can keep the memory locked without serious effect, because the 386 can
still swap memory out to the swapfile.  But don't PageLock all your memory.

Mojo

-- 
mojo@netcom.UUCP          Site Coordinating Instructor, San Jose South
Morris "Mojo" Jones       Skilled Motorcycling And Rider Training (S.M.A.R.T.)
Campbell, CA              800-675-5559 ... 800-CC-RIDER ...  408-423-2212
AA4KB @ N6LDL.#NOCAL.CA.USA.NA / aa4kb.ampr.org / netcom!mojo@apple.com

billf@progress.COM (Bill Ferro) (12/20/90)

nickel@cs.utexas.edu (Jody P. Nickel) writes:

>If you are only going to run in 386 enhanced mode the this will simplify
>your task immensely. After a GlobalAlloc, you can lock this memory and
>leave it locked until it is no longer needed. The far pointer you receive
>is a selector:0 pointer.

	This is also true for standard mode.  Malloc and Free code
examples follow:

char	*malloc(nbytes)
	WORD	nbytes;
{
	HANDLE h;

	if ((h=GlobalAlloc(GMEM_MOVEABLE,DWORD(nbytes))) == NULL)
		return ((char *)0);
	else
		return ((char *)GlobalLock(h));
}

void	free(ptr)
	char	*ptr;
{
	HANDLE h;

	h = LOWORD(GlobalHandle(HIWORD(ptr)));
	GlobalUnlock(h);
	GlobalFree(h);
	return;
}

-bf
--
Bill Ferro			UUCP: mit-eddie!progress!billf
Progress Software Corp.		Internet: billf@progress.com
5 Oak Park
Bedford, MA  01730

jason@media-lab.MEDIA.MIT.EDU (Jason A. Kinchen) (12/20/90)

In article <1990Dec19.194631.22880@progress.com> billf@progress.COM (Bill Ferro) writes:
>nickel@cs.utexas.edu (Jody P. Nickel) writes:
>
>>If you are only going to run in 386 enhanced mode the this will simplify
>>your task immensely. After a GlobalAlloc, you can lock this memory and
>>leave it locked until it is no longer needed. The far pointer you receive
>>is a selector:0 pointer.
>
>	This is also true for standard mode.  Malloc and Free code
>examples follow:
>
[here was the most often written Windows code in the world.}

Okay, now here's one for you.  GlobalAlloc can take a long or DWORD
(32 bit) and therefore has a 4 Gigabyte address space.  However, they
warn you in the Guide to Programming that if you allocate more than
64K the returned pointer must be cast and saved as a huge pointer so
the proper segment arithmetic is done.  Has anyone solved the problem
of dynamically, globally alloc'ing an arbitrarily long block of memory
when you don't know in advance if it's longer than 64K?  Do you have
to compile huge model or something nasty like that?

Thanks in advance.
-- 
Jason Kinchen
jason@media-lab.MIT.EDU

nadkarni@ashok.dec.com (Ashok P. Nadkarni) (12/20/90)

In article <588@rodan.cs.utexas.edu>, nickel@cs.utexas.edu (Jody P. Nickel) writes...
>If you are only going to run in 386 enhanced mode the this will simplify
>your task immensely. After a GlobalAlloc, you can lock this memory and
>leave it locked until it is no longer needed.

As far as I know, this is also true in standard mode. It's only real mode that
you need to worry about being a good citizen in terms of unlocking global
memory.

/Ashok Nadkarni

mojo@netcom.UUCP (Morris Jones) (12/21/90)

jason@media-lab.media.mit.edu (Jason A. Kinchen) writes:
>                                        Has anyone solved the problem
>of dynamically, globally alloc'ing an arbitrarily long block of memory
>when you don't know in advance if it's longer than 64K?  Do you have
>to compile huge model or something nasty like that?

Here's one option if you're on a 386:  See Appendix E of the SDK manual.
Use the function Global32Alloc.  The selector you get back well be a USE32
selector, thus requiring a 32-bit offset.

Now the problem comes in referencing all that memory from a 16-bit program.
You can get 16-bit pointers into the memory using Global16PointerAlloc, but
each pointer will be limited to a 64K segment of space.

If you write some assembler, you can reference the memory using the 32-bit
registers, or other bits of 386-specific code.

Just some food for thought ...

Mojo

-- 
mojo@netcom.UUCP          Site Coordinating Instructor, San Jose South
Morris "Mojo" Jones       Skilled Motorcycling And Rider Training (S.M.A.R.T.)
Campbell, CA              800-675-5559 ... 800-CC-RIDER ...  408-423-2212
AA4KB @ N6LDL.#NOCAL.CA.USA.NA / aa4kb.ampr.org / netcom!mojo@apple.com

nickel@cs.utexas.edu (Jody P. Nickel) (12/22/90)

This isn't pretty but... And I'm sure Microsoft won't condone it. The pointer
returned will always be an XXXX:0000, where XXXX is the selector for the
first 64K of the memory. To get to the next 64K you need to increment the
selector by (I'm not %100 of the value) 8. The easiest way to do this is
using the _based keyword and a far *; Something like the following.

_segment BigSeg;
char _based(BigSeg) *pBigSeg;

void far *x;
x=GlobalLock(...);
BigSeg=FP_SEG(x);
pBigSeg = NULL;

Now pBigSeg is pointing at the first 64 K and can move through it with ease. To
get at the next 64K, increment BigSeg by 8, reset pBigSeg to 0 and now you
have the next 64K. This by no means is any easier than using a huge model pointer
but if you don't want to use the huge memory model this, or something like it
is the only alternative.

Disclaimer..
Use at your own risk, if Microsoft choses to change the way these huge blocks
are mapped into the LDT this code won't work. (But neither will the programs

goodearl@world.std.com (Robert Goodearl) (12/22/90)

In article <600@rodan.cs.utexas.edu> nickel@cs.utexas.edu (Jody P. Nickel) writes:
>This isn't pretty but... And I'm sure Microsoft won't condone it. The pointer
>returned will always be an XXXX:0000, where XXXX is the selector for the
>first 64K of the memory. To get to the next 64K you need to increment the
>selector by (I'm not %100 of the value) 8. The easiest way to do this is
>using the _based keyword and a far *; 

If you _were_ going to manipulate the segment register yourself, you would add
16 NOT 8.  HOWEVER, this is specifically recommended against.  You CAN declare
huge pointers without compiling entirely in the huge model.  I believe this
is much better than trying to manipulate segment registers yourself.
-- 
Bob Goodearl -- goodearl@world.std.com

mojo@netcom.UUCP (Morris Jones) (12/22/90)

nickel@cs.utexas.edu (Jody P. Nickel) writes:
>This isn't pretty but... And I'm sure Microsoft won't condone it. The pointer
>returned will always be an XXXX:0000, where XXXX is the selector for the
>first 64K of the memory. To get to the next 64K you need to increment the
>selector by (I'm not %100 of the value) 8.

WAIT hold on there just a moment.  The value might not always be 8.

But SUPPOSEDLY you can be sure by adding the contents of the variable
_ahincr.

Check that out.  I'm pretty sure that's what the SDK says, and that's
how C generates code for huge pointers.

Mojo
netcom!mojo@apple.com
-- 
mojo@netcom.UUCP          Site Coordinating Instructor, San Jose South
Morris "Mojo" Jones       Skilled Motorcycling And Rider Training (S.M.A.R.T.)
Campbell, CA              800-675-5559 ... 800-CC-RIDER ...  408-423-2212
AA4KB @ N6LDL.#NOCAL.CA.USA.NA / aa4kb.ampr.org / netcom!mojo@apple.com

davidds@microsoft.UUCP (David D'SOUZA) (12/26/90)

In article <600@rodan.cs.utexas.edu> nickel@cs.utexas.edu (Jody P. Nickel) writes:
>This isn't pretty but... And I'm sure Microsoft won't condone it. The pointer
>returned will always be an XXXX:0000, where XXXX is the selector for the
>first 64K of the memory. 

You are pretty much assured that a GlobalAlloced memory block starts at
offset 0.  MS certainly can't change this without some form of 
backwards compatbility for all the apps that already depend on this...

>To get to the next 64K you need to increment the
>selector by (I'm not %100 of the value) 8. The easiest way to do this is
>using the _based keyword and a far *; Something like the following.

You are pretty much assured to break if you assume anything like this.

>Now pBigSeg is pointing at the first 64 K and can move through it with ease. To
>get at the next 64K, increment BigSeg by 8, reset pBigSeg to 0 and now you
>have the next 64K. This by no means is any easier than using a huge model pointer
>but if you don't want to use the huge memory model this, or something like it
>is the only alternative.

If you are using C, you can declare pointers to be HUGE and the C
compiler  will do the right thing for you. You don't have to be huge
model.  Just like you can declare FAR pointers if you are small model, 
you can declare HUGE pointers...  There shouldn't be too many reasons
you should worry about selector tiling if you are using C since the
compiler takes care of this for you...


If you are using asm, your code should be as follows:

ExternA <__AHINCR> ; This external is exported by Windows kernel and you
                   ; will get the proper value to increment your selectors
                   ; by independent of which mode of windows you are running
                   ; (ie. real, standard, and enhanced have different values)
                   ; BTW: That's two underscores before the A.

mov ax, es	
add ax, __AHINCR ; move es up 64K or to the next selector
mov es, ax

The C compiler generates code which links to __AHINCR  exported from
Kernel so  it always works.

sdw@hpsad.HP.COM (Steve Warwick) (01/10/91)

Both the SDK and Petzold's book seem to avoid detailing how 
windows deals with movable code and data segments in protected
mode programs. They instead concentrate on the software-assisted
fixup methods which are required in real mode. Assuming you are willing
to write applications which are restricted to protected mode, is there a
clean description of the assumptions you can make about segments i.e.

1) can you assume that program code and segments are fixed 
 (since they are segment selectors)

2) won't  large model programs work fine, since data segments are also
  segment selectors..

3) same for DLL code and data?

more generally,

4) How does windows protected mode differ from OS/2 protected mode 
     in terms of segment fixups,  relocation and virtual memory?

5) Arn't much simpler methods of dealing with code and data movement 
	available when your in protected mode, removing the need for 
	windows prolog/epilogs and thunks? Will future versions of windows
	support such simpler models?


References to articles/technical publications dealing with these
issues will be appreciated. Please avoid the "I Think That ..."
(Unless you wrote it...)

petergo@microsoft.UUCP (Peter GOLDE) (01/14/91)

Microsoft Systems Journal has discussed this issue in fairly good
detail in the last 2 issues (and maybe others?).