🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.sys.amiga.tech
Article #11933

Re: CBM, Why did you make it so hard?

#11933
From: Michael "Ford" Ditto
Date: Thu, 23 Mar 1989 17:16
157 lines
7788 bytes
In article <933@dover.azsps.mot.com> fullmer@dover.UUCP (Glen Fullmer) writes:
>The essential
>question was: How does one maintain session context (reentrancy) in an
>Amiga run-time library when multiple sessions use a set of changing
>globals?  There was a couple of suggestions: (1) To require the user
>to create a session context pointer (like Raster-Pointer in Intuition)
>or (2) to maintain a session context table within the library.

Since the reason given for prefering (2) was to eliminate the need for
a user to carry around this useless (as far as the program can see)
pointer, why not solve all the problems mentioned by hiding that
detail in the link part of the library (the part that would normally
just jsr to the shared library routine).  Since this is already done
anyway with the library base pointer itself, just make this "context"
pointer a "hidden" variable as well.

>OK,  let's try a concrete example.  I have a graphics system that
>is a collection of library routines that can  be  called  by  the
>user.   The  user  must call "gstart" first.  He must call "gend"
>when finished using the library.   There  is  a  function  called
>"gdraw"  that  the  user  can  call  to  draw a line.

/* simplified code -- this is linked with the user's program:  */

static struct Library *__glibbase; /* library base */
static void *__context;		/* "session handle" for this task */

int gstart()
{
    if (!__glibbase)		/* open the library */
	__glibbase = OpenLibrary("glib.library", 0);
    if (__context)		/* only one session at a time in this task */
	return -1;
    __context = _gstart();	/* _gstart is the "glue" function */
    return __context != 0;
}

void gend()
{
    _gend(__context);		/* another glue function */
    __context=0;		/* we could now gstart() again if desired */
    /* perhaps CloseLibrary(...) */
}

void gdraw(arg1, arg2)
{
    _gdraw(__context, arg1, arg2); /* another glue function */
}


With that method, you get the best of both worlds:

	+ The glib.library itself is effecient.
	+ Users have a convenient interface.
	+ Users can directly call the _functions if they want to
	  have multiple sessions.


>So  the  problem  on  the  Amiga  is how to set up a library with
>task-dependent   global/persistent   storage   that,   after    a
>time-share  interrupt  or  other  interrupt,  remembers where its
>particular task-dependent global/persistent storage area is  when
>it  again  receives  control  from  the scheduler.  I so far have
>placed  all  of  the  global/persistent  storage  items  in   one
>structure.   I  can  use  MemAlloc  to  allocate  storage for the
>area.  The problem is how to  preserve  that  pointer  through  a
>time-share   interrupt   (or   any  other  sort  of  asynchronous
>interrupt that takes control away from me, runs  something  else,
>then returns to me.)

You're trying real hard to find a way to do things the hard way.  :-)

Just don't worry about interrupts.  You'll never know they happened.
If you have the session pointer in an automatic (stack or register)
variable, you can access it as you like, even if another task is
also running your library.  Each task has its own stack and registers,
and you don't need to worry about what happens to yours during or
after an interrupt or task switch.

>During   an  interrupt,  70  bytes  are  pushed  onto  the  stack
>representing  all  of  the  data  registers,  address  registers,
>status   register,  and  the  program  counter.   When  you  find
>yourself back in your code after an  interrupt,  those  70  bytes
>are  all  you  really  know.

Well, those bytes + everything else you ever knew.  None of your
data will change during an interrupt or task switch unless you
change them.

>   (You  wouldn't even know where the
>stack was unless one of the registers was dedicated to holding  a
>pointer  to  it.)

No, you could keep a copy of it in any register you like.  There
are no "dedicated" registers as far as context switches go.  ALL
your registers will be saved.  And besides, IT DIDN'T MOVE, so
you know where it is just as well as you did before the interrupt.

>   Clearly,  the best way to save a pointer to a
>task-dependent global/persistent storage area is to DEDICATE  one
>of  the  registers,  say A3, to always holding the pointer to the
>task-dependent  global/persistent  storage  area.

You can do this if you like; but nobody but your code will ever
know or care.  You might as well just put it in an automatic
variable, any one will do.  Dedicating a register to hold that
pointer whenever in your library code is just another way of
passing a parameter to all the functions in your library.  You
still need to load that pointer when your library is called
from the user program, and restore the registers when you return.

>   This  is  how
>Multics  achieved  what  I  consider  to  be  true  reentrancy  -
>reentrancy with per process global/persistent data - and  spoiled
>me  beyond  words...   (See page 68 of "Timesharing System Design
>Concepts",  Richard  Watson,  McGraw-Hill,  1970.   The   Multics
>operating  system,  by  convention, dedicates a hardware register
>called a "link pointer" to the "linkage information",  i.e.,  the
>task-dependent   storage.   This  is  always  restored  after  an
>interrupt so the task ALWAYS knows  where  its  own  storage  is.

ALL registers are restored after an interrupt (in Exec and any
other OS I've used; I really can't imagine that Multics is any
different).  I think what you are asking for has nothing to do
with interrupts; you just want this magic pointer to always be
there for you.  The way to make this happen is to pass it in
as an argument to all your functions.  The user doesn't have to
do this, you could do it at the entry to the library or in the
glue routines that the user links with.

 [ description of using FindTask(0) to recognize a previous
   caller and search for its state information ]

This would work also, but it seems that you are stuck on the idea
of closely tying a "session" to a task, limiting each task to
only one active session.  Why go to the trouble of "True
Reentrancy" without allowing multiple sessions within a task?  If
you want to provide a convenient interface, that's great, but keep
the basic structure as flexible and efficient as possible, and put
the convenience as a layer on top.  That way when a user comes
along who prefers flexibility to convenience, your library won't
be in the way.

>Is there an easier way to do what I want to do?

I think you're trying to do many unnecessary things.  It's obvious
that you know about the complexities of reentrant programming, but
I think you must have learned them on a very strange system.  :-)
Perhaps it would help to get the source code to a library and see
how things are typically done.
-- 
					-=] Ford [=-

"The number of Unix installations	(In Real Life:  Mike Ditto)
has grown to 10, with more expected."	ford@kenobi.commodore.com
- The Unix Programmer's Manual,		...!sdcsvax!crash!kenobi!ford
  2nd Edition, June, 1972.		ditto@cbmvax.commodore.com
Technical Details
Message-ID: <6379@cbmvax.UUCP>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!ames!oliveb!amiga!cbmvax!ditto
References: <913@dover.uucp> <3623@amiga.UUCP> <933@dover.azsps.mot.com>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!ames!oliveb!amiga!cbmvax!ditto
From: ditto@cbmvax.UUCP (Michael "Ford" Ditto)
Newsgroups: comp.sys.amiga.tech
Subject: Re: CBM, Why did you make it so hard?
Summary: It's not *that* difficult
Keywords: Graphics Libraries, reentrancy
Message-ID: <6379@cbmvax.UUCP>
Date: 23 Mar 89 17:16:02 GMT
References: <913@dover.uucp> <3623@amiga.UUCP> <933@dover.azsps.mot.com>
Reply-To: ditto@cbmvax.UUCP (Michael "Ford" Ditto)
Organization: Commodore Technology, West Chester, PA
Lines: 157