[comp.sys.mac.programmer] Help With VBL Tasks

borcelf@jacobs.cs.orst.edu (Fernando Borcel) (01/19/89)

I Started messing around with VBL tasks just today, following my IM II direc-
tions.  Now, I wore this rather silly task, just to see what it does, and it
worked (oh, surprise!), but for just a few times, bombing bad afterwards.

Here's what I wrote:

 procedure myVbl;
  var
   VBLTask : QElemPtr;
 begin
  SetUpA5;

  FlashMenuBar(0);  {my "TASK"}

  new(VBLTask);
  VBLTask^ := myVBLTask^;
  if vInstall(VBLTask) <> NoErr then  {Enqueue for Next VBL task}
   exitToShell;

  RestoreA5;
 end;


{later in the code, something I call only ONCE}
...
...
  new(MyVBLTask);
  with MyVBLTask^.VBLQElem do
   begin
    qtype := ord(vtype);
    vbladdr := @myVBL;
    vblCount := 5;
    vblPhase := 0;
   end;

  new(VBLTask);  {I decided to use a copy of the task}
  VBLTask^ := MyVBLTask^;
  if vInstall(VBLTask) <> NoErr then
   exitToShell;



---

I tried many other combinations, but none of them worked any better...

	Thanks.

    ___                       __                |{tektronix,hp-pcd}!orstcs!
   /   _  _  _  _  _  _/ _   /_/  _  _  _  _ /  |  jacobs.cs.orst.edu!borcelf
  /- /_// // / _// // // /  /  )/ // //  /_//   | 
_/  /_ /  / //_// //_//_/  /__//_//  /_ /_ /_   |borcelf@jacobs.cs.orst.edu 

lsr@Apple.COM (Larry Rosenstein) (01/20/89)

In article <8343@orstcs.CS.ORST.EDU> borcelf@jacobs.cs.orst.edu (Fernando Borcel) writes:

>Here's what I wrote:
>
> procedure myVbl;
>  var
>   VBLTask : QElemPtr;
> begin
>  SetUpA5;
>
>  FlashMenuBar(0);  {my "TASK"}
>
>  new(VBLTask);
>  VBLTask^ := myVBLTask^;
>  if vInstall(VBLTask) <> NoErr then  {Enqueue for Next VBL task}
>   exitToShell;
>
>  RestoreA5;
> end;

There are a couple of problems here:

(1) A VBL task runs at interrupt level, and can't call any routins that
allocate memory.  FlashMenuBar does allocate memory (it's listed in the
chart in Inside Mac).  I suspect that New could also.

(2) The technique you use to set up the task to be executed again is not
right.  You don't need to creata new task block.  Instead you shouldsimply
reset the vbl counter in the existing task block.  A pointer to the task
block is passed in A0 when your VBL code is called.  There are various ways
to get this register in Pascal, depending on the development system.

Your initial installation code looks OK to me.


-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

oster@dewey.soe.berkeley.edu (David Phillip Oster) (01/20/89)

n addition to all the previous problems, most versions of SetUpA5() look
at a global variable, CurrentA5, which is not guaranteed to be correct
under multifinder.

lsr@Apple.COM (Larry Rosenstein) (01/21/89)

In article <27628@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) writes:
>n addition to all the previous problems, most versions of SetUpA5() look
>at a global variable, CurrentA5, which is not guaranteed to be correct
>under multifinder.


Tech Note 208 also mentions a problem in that SetupA5 saves the current A5
on the stack, which screws up some optimizing compilers (eg, MPW C 3.0).
It suggests that you save the current A5 value in a local place and restore
it at the end.

-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

borcelf@jacobs.CS.ORST.EDU (Fernando Borcel) (01/21/89)

In article <445@internal.Apple.COM> lsr@Apple.COM (Larry Rosenstein) writes:
>
>(2) The technique you use to set up the task to be executed again is not
>right.  You don't need to creata new task block.  Instead you shouldsimply
>reset the vbl counter in the existing task block.  A pointer to the task
>block is passed in A0 when your VBL code is called.  There are various ways
>to get this register in Pascal, depending on the development system.
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  

OK, I'm using LSPascal.  How do I get A0, and what is the TYPE of what it's
pointed by it?


	Fernando

    ___                       __                |{tektronix,hp-pcd}!orstcs!
   /   _  _  _  _  _  _/ _   /_/  _  _  _  _ /  |  jacobs.cs.orst.edu!borcelf
  /- /_// // / _// // // /  /  )/ // //  /_//   | 
_/  /_ /  / //_// //_//_/  /__//_//  /_ /_ /_   |borcelf@jacobs.cs.orst.edu 

tim@hoptoad.uucp (Tim Maroney) (01/21/89)

In article <27628@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP
(David Phillip Oster) writes:
>In addition to all the previous problems, most versions of SetUpA5() look
>at a global variable, CurrentA5, which is not guaranteed to be correct
>under multifinder.

In article <451@internal.Apple.COM> lsr@Apple.COM (Larry Rosenstein) writes:
>Tech Note 208 also mentions a problem in that SetupA5 saves the current A5
>on the stack, which screws up some optimizing compilers (eg, MPW C 3.0).
>It suggests that you save the current A5 value in a local place and restore
>it at the end.

However, this doesn't address the fact that you may need a different A5
from the one in CurrentA5, which was David's point.  This may happen in
interrupt driven code that is not switched by MultiFinder.  VBL tasks
only run when their application has the processor, but not so things
like socket listeners or custom interrupt handlers.  I still don't know
any way around this except for stashing a copy of your A5 in
code-relative space, which is explicitly forbidden (with good reason)
by Tech Note #2.  I'm not even sure that Apple acknowledges that this
is a problem; when I pointed it out to David Goldsmith a couple of
years back, he just started shouting angrily....
-- 
Tim Maroney, Consultant, Eclectic Software, sun!hoptoad!tim
"The above opinions and suggestions have absolutely nothing to do with
 the little, fat man putting crisp, $100 bills in my pocket."
    -- Alan Vymetalik

paul@taniwha.UUCP (Paul Campbell) (01/23/89)

In article <6347@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>interrupt driven code that is not switched by MultiFinder.  VBL tasks
>only run when their application has the processor, but not so things
>like socket listeners or custom interrupt handlers.  I still don't know
>any way around this except for stashing a copy of your A5 in
>code-relative space, which is explicitly forbidden (with good reason)
>by Tech Note #2.  I'm not even sure that Apple acknowledges that this

Yes! Yes! I'm forever running into this problem, when you want to find
a 'global' object in the Mac (ie the context of an INIT to communicate
with it, or some completion routines and their apps) often it's a real
pain. The real problem is one of 'naming' how can I have two items agree
on a name to find a common item if they don't have common context, often
the problem can be solved by extending the parameter block involved (for
example VBL's or completion routines). I once had to go to the extent of
writing a driver (don't ask!) so that I had a common 'name' that could
be accessed by apps, a cdev and another driver! In many ways this may be
a better way to do it in the long run (ie with whatever they end up doing
with the MMU etc) because it uses a trap to get from local context to
the global context, and the trap handling code (the driver's Control routine)
can do all the inter-context manipulation (but then this is starting to
sound a lot like how people hack around this stuff in Unix, which is after
all my bias ....).

On the other hand somethimes Apple do do it right! The 'A1Param' in the
slot SIntInstall is a good example, one can carry as much baggage as one
likes there, simply by using it as a pointer to a locked data structure.

	Paul
-- 
Paul Campbell			..!{unisoft|mtxinu}!taniwha!paul (415)420-8179
Taniwha Systems Design, Oakland CA

    "Read my lips .... no GNU taxes" - as if they could tax free software

lsr@Apple.COM (Larry Rosenstein) (01/24/89)

In article <6347@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>
>However, this doesn't address the fact that you may need a different A5
>from the one in CurrentA5, which was David's point.  This may happen in

Definitely true.  In fact, I wouldn't recommend using CurrentA5 any more.
The times when you need to setup A5 are in interrupt routines, and
generally, you can't count on CurrentA5 under MultiFinder.  (Although I
think there are some cases where it is OK to use CurrentA5, it is best not
to take chances.)

>like socket listeners or custom interrupt handlers.  I still don't know
>any way around this except for stashing a copy of your A5 in
>code-relative space, which is explicitly forbidden (with good reason)
>by Tech Note #2.  I'm not even sure that Apple acknowledges that this
>is a problem

This is clearly acknowledged in Tech Note 180.  Some routines that run at
interrupt level are given pointers to parameter blocks, etc. where the
desired A5 could be stashed.  (VBL tasks are one of these.)

Some routines don't have any place to store A5, so the Tech Note recommends
storing the desired A5 into your code area.  This applies to Time Manager
tasks and interrupt service routines.

-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

lsr@Apple.COM (Larry Rosenstein) (01/24/89)

In article <8383@orstcs.CS.ORST.EDU> borcelf@jacobs.CS.ORST.EDU.UUCP (Fernando Borcel) writes:
>
>OK, I'm using LSPascal.  How do I get A0, and what is the TYPE of what it's
>pointed by it?

Here is a simple LSP 2.0 program that shows how to use VBLs.

It sets up a VBL task that runs every 2 seconds.  That task increments a
global variable.  The main program loops checking the variable and printing
it when it changes.  When you click the mouse the program stops.

I don't know if the GetA0 technique is absolutely safe.  It depends on the
compiler not using A0 for anything before the start of the vbl task.  It
seemed to work in this case.  

A safer technique is to write a short assembler routine that gets A0 and
passes it as a parameter to your Pascal routine.  But this requires some
other development system that can generate assembler code.  (Eg, MPW or
LSC.) 

***********

program VBLTest;


var
  myRecord: record
      mya5: LONGINT;
      vblBlock: VBLTask;
    end;
  state: INTEGER;

{ INLINES to manipulate A5 }

function GetA5: LONGINT;
inline
  $2E8D; {MOVE.L A5,(A7)}

function LoadA5 (newA5: LONGINT): LONGINT;
inline
  $2F4D, $0004, $2A5F;


{ INLINE to get A0 in the task }
function GetA0: LONGINT;
inline
  $2e88;


{ Can't do debugging at interrupt level }
{ don't want to use $A+ because it uses CurrentA5 }

{$D-}
procedure VBL;
  var
    err: OSErr;
    curA5: LONGINT;
    p: ^LONGINT;

  begin
{ Get the pointer to myA5 }
    p := Pointer(GetA0 - 4);

{ Set A5 }
    curA5 := LoadA5(p^);

{ Here's where you do something. }
    state := state + 1;

{ Reset the VBL counter }
    myRecord.vblBlock.vblCount := 120;

{ Restore A5 }
    curA5 := LoadA5(curA5);
  end;
{$D+}


  var
    err: OSErr;
    old: integer;
    ev: EventRecord;

begin
{ Initialize A5 }
  myRecord.mya5 := GetA5;
  state := 0;
  old := 0;

  showtext;

  with myRecord.vblBlock do begin
    qType := Ord(vType);
    vblAddr := @VBL;
    vblCount := 120;
    vblPhase := 0;
  end;
  err := VInstall(@myRecord.vblBlock);
  writeln('err=', err);

  while true do begin
    if old <> state then begin
      old := state;
      writeln(old);
    end;

    if GetNextEvent(-1, ev) then begin
      if ev.what = mouseDown then
        leave;
    end;
  end;

  err := VRemove(@myRecord.vblBlock);
  writeln('err=', err);
end.-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr