🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

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

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

#11926
From: Glen Fullmer
Date: Wed, 22 Mar 1989 23:20
174 lines
10388 bytes
In article <3623@amiga.UUCP> jimm@cloyd.UUCP (Jim Mackraz) writes:
>)3.  How does one restore the environment, for example, after an interrupt?
>
>I don't follow.  Unless you are using interrupts as part of the package,
>the system will restore you without your ever knowing.  All registers must
>...
>)4.  Is making a package that must retain context both over the life of a 
>)    call and the life of the session different than  "pure" residentable
>)    code?  If so, how are they different, and what are the coding 
>)    differences?
>
>Most system libraries don't have a notion of "session," that is, there is
>typically no preserved state.  To do this, you would just introduce
>a "handle" that is returned by InitSession() and passed to every pertinent
>call (including EndSession()).  I guess you could say the OpenWindow() is
>doing just that.  Think also about the model of a RastPort: it isn't
>session-based, but it is a handle.  It has an Init() (although no Create()),
>and no End().
>Jim Mackraz, I and I Computing	   	"Like you said when we crawled down
>{cbmvax,well,oliveb}!amiga!jimm          from the trees: We're in transition."
>							- Gang of Four

I want to thank all those who responded to my original inquiry about
Amiga run-time libraries.  It was very helpful and enlightening.
Howard Anderson, whose generic graphics system originally elicited the
questions, also appreciated the comments.

There was some misunderstanding concerning my reference to interrupts.
No, he is not using interrupts as part of the package.  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. He had
some additional comments about his preference to (2) and questions
about methods to achieve it.  Any other methods that I missed?  As it
is more convenient for me to post news than he, I am including his
comments and questions:


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.  There is a
function called "gset" that allows one to change modes,  such  as
the  drawing  color,  that  will  be  used for subsequent "gdraw"
calls.  There are of course a lot of other callable functions  in
the library. 

I  don't  want  the  user  to  have  to  bother with setting up a
graphics structure for the graphics system.   I  don't  want  the
user  to  have to bother with passing some structure pointer that
is irrelevant to  doing  graphics.   Since  the  graphics  system
library  is  the  object that NEEDS the structure for saving mode
data, it should  do  its  own  allocation,  pointer-finding,  and
deallocation  of  its  task-dependent  global/persistent storage.
The purpose of putting a generic graphics system up on the  Amiga
is to make it easier for the user to use. 

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.)

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.   (You  wouldn't even know where the
stack was unless one of the registers was dedicated to holding  a
pointer  to  it.)   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.   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  programs are shared.  New storage for task-dependent data of
a called function is always allocated whenever that  function  is
first  called by a new process.  On Multics, the operating system
takes care of all reentrancy/data mechanics.)

If I had written the graphics  system  in  assembly  language,  I
could  have  dedicated  a register to point to the task-dependent
storage.  This register would have to be reserved  and  untouched
in  the  user  program that calls the library function of course.
There does not appear to be a way  to  do  that  if  the  calling
program is written in C. 

My  best  guess  at  present  is  that  to  fake  reentrancy with
per-process global/persistent data, for a program written  in  C,
where   the   shared  code  is  responsible  for  allocating  and
deallocating its own global/persistent storage automatically,  is
to  use  FindTask  with  a  null argument to get a pointer to the
current task, then use tc_UserData as a storage location for  the
pointer  to  the task-dependent global/persistent storage area --
IF the Amiga designers meant for tc_UserData to be  used  by  ME.
Did  they?  My documentation says "per task data" but doesn't say
WHOSE.  (I see that it is NULL from within a CLI task.)

Now even if I have that, I don't exactly like  it.   My  "gstart"
routine  would  have  to call Forbid(), then FindTask so that the
pointer could be stored in tc_UserData.  Then  I  would  have  to
store  the  pointer in a local automatic variable for further use
within "gstart" then I'd have to call Permit().   That  would  be
OK  but EACH routine in the graphics library, subsequently called
by the user program,  would  have  to  call  FindTask  to  locate
tc_UserData  and  store the pointer in a local automatic variable
so that graphics mode  data  could  be  referenced  through  that
structure pointer.  What is the overhead for a FindTask?

Now  assuming  the  Commodore/Amiga  people  really don't want me
mucking around with tc_UserData, I could define a 2xn  vector  in
static  storage  that  would  contain  the address of the current
task block as determined by  a  FindTask  call  paired  with  the
address  of  the  corresponding  global/persistent  storage area.
Then EACH routine in the graphics  library  would  have  to  call
FindTask,  to  get the task block pointer, then search the vector
for  that  pointer  which  would   yield   the   index   of   the
corresponding  address  of  global/persistent  storage so that it
could be placed in a local automatic variable.  I don't like  the
idea  of  having  to  search  that vector even though I know some
great hash algorithms. 

So I really don't like any of the alternatives very well.   Am  I
missing something?

I  figured  out  how to link to a library and pass floating point
variables.  I know how to DO  reentrant  code  with   per-process
global/persistent  data.   I'm  just  not  sure  if  there  is an
efficient way to do it in C on the  Amiga.   I  definitely  don't
like  the  idea  of  the  user  having  to pass a pointer to each
routine he calls as is done with RPort. 

All of this began of course with  the  fact  that  the  Manx  and
Lattice  compilers  cannot  link each other's object segments.  I
had originally intended to create a library  of  object  segments
for  linking  in  with  the  user  program.   Most  of the larger
machines I've worked with such as the Philco  2000,  IBM  360/85,
3094-Q,  Honeywell  6080,  Multics  and  even Sun and Apollo have
standard linkers on the system provided as part  of  the  system.
(At  least  I've always thought they were provided as part of the
system.)  On smaller machines I've worked on such  as  the  Apple
II  and  C-64,  the  linkers  appear  to  have  been specified by
third-party  software  suppliers.   The  shared  library   method
however  seems to be a better answer than a link library if I can
get it to work the way I want it to. 

I like the Amiga  a  lot.   Don't  misconstrue  any  of  this  as
criticism  of the design.  Commodore/Amiga did a rather brilliant
job.  I am just trying to understand the Amiga conventions  while
attempting  to  implement some software whose interface I want to
conform to some of my conventions. 

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

  _____     _  "For a successful technology, reality must take precedence" 
 {____/    //  "over public relations, for Nature cannot be fooled."
      \   // _  __Richard P. Feynman, Appendix F of Shuttle Disaster Report
 {____/  </_</_/ / <_  {sun!sunburn | cadillac} !dover!fullmer   
-- 
Technical Details
Message-ID: <933@dover.azsps.mot.com>
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!lll-winken!ames!pasteur!ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!oakhill!dover!fullmer
References: <913@dover.uucp> <3623@amiga.UUCP>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!lll-winken!ames!pasteur!ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!oakhill!dover!fullmer
From: fullmer@dover.azsps.mot.com (Glen Fullmer)
Newsgroups: comp.sys.amiga.tech
Subject: Re: CBM, Why did you make it so hard?
Keywords: Graphics Libraries, reentrancy
Message-ID: <933@dover.azsps.mot.com>
Date: 22 Mar 89 23:20:51 GMT
References: <913@dover.uucp> <3623@amiga.UUCP>
Reply-To: fullmer@dover.UUCP (Glen Fullmer)
Organization: Motorola CAD, Mesa
Lines: 178