[comp.sys.mac.programmer] Background MAGIC

moyman@ecn.purdue.edu (James M Moya) (08/10/90)

How is it that cdev/INIT's like Moire and SuperClock (and many others) can 
run in the background whether multifinder is running or not!!  I have been 
checking every mac bnook I know of to learn of this black magic...NOTHING.

Exactly what is it they are doing?? Or does anybody *really* know...

I have an "appletalk" listener I am writing (cdev/INIT) that I want to come
forward with a dialog when it recieves a particular packet...This should
work whether Multi is running or not...I haven't been able to find 
*anything* in IM or any other book for that matter...I am frazzled at
this point...Anybody with some insight to help a man on the brink...



Mike Moya
Systems Programmer
Engineering Computer Network
Purdue University

jackiw@cs.swarthmore.edu (Nick Jackiw) (08/10/90)

moyman@ecn.purdue.edu (James M Moya) writes:
> How is it that cdev/INIT's like Moire and SuperClock (and many others) can 
> run in the background whether multifinder is running or not!!  I have been 
> checking every mac bnook I know of to learn of this black magic...NOTHING.
> 
> Exactly what is it they are doing?? Or does anybody *really* know...
> 
> I have an "appletalk" listener I am writing (cdev/INIT) that I want to come
> forward with a dialog when it recieves a particular packet...This should
> work whether Multi is running or not...I haven't been able to find 
> *anything* in IM or any other book for that matter...I am frazzled at
> this point...Anybody with some insight to help a man on the brink...
> 
> 
> 
> Mike Moya
> Systems Programmer
> Engineering Computer Network
> Purdue University


-- 
-----Nicholas Jackiw [jackiw@cs.swarthmore.edu|jackiw@swarthmr.bitnet]-----
"Here is how I built this artificial mine. I snatched a female louse from the
hair of humanity. I was seen to lie with her on three successive nights, and
then I flung her into the pit."       _Maldoror_, Canto II

jackiw@cs.swarthmore.edu (Nick Jackiw) (08/10/90)

Sorry about that blank posting--MacIP trashed my window and I was
typing blind.  

moyman@ecn.purdue.edu (James M Moya) writes:
> How is it that cdev/INIT's like Moire and SuperClock (and many others) can 
> run in the background whether multifinder is running or not!!  I have been 
> checking every mac bnook I know of to learn of this black magic...NOTHING.
> 
> Exactly what is it they are doing?? Or does anybody *really* know...

Multifinder only schedules applications, and thus has nothing to do with
init/cdevs.  Instead, these programs install their code (usually into
the system heap) while their INIT section is running.  Then, they alter
the system environment somewhat so that their code gets called periodically.
The two most popular ways of doing this are by patching a trap which you
can count on all applications calling frequently (e. g. SystemTask) or
which is relevant to your particular task (e. g. MenuSelect, if your
init/cdev dynamically altered application menus), or by installing an
interrupt handler which is invoked by the vertical blanking interval
interrupt.  When either the trap is called or the VBL fires, the code
they've loaded into the system heap is executed, allowing them to, say,
check whether User's been idle for the predetermined time (Moire) or
whether the clock has ticked (Superclock).

> > 
> > I have an "appletalk" listener I am writing (cdev/INIT) that I want to come
> > forward with a dialog when it recieves a particular packet...This should
> > work whether Multi is running or not...I haven't been able to find 
> > *anything* in IM or any other book for that matter...I am frazzled at
> > this point...Anybody with some insight to help a man on the brink...

There are problems inherent in forcing your own dialog from out of the wood-
work on some foreground application. What if, for example, that application
hasn't called _InitDialogs, which must be done before any dialog manager
use?  (There are many other problems, too.)  TechNote#184, and a chapter
in Inside Mac#6, describe the Notification Manager, a built-in way for
background applications and other "faceless code" (like an init/cdev) to
issue a dialog which minimizes these compatibility problems.  The dialog
is pretty limited--you can have some canned text and only one button.
However, this dialog can instruct the user to take some action which will
allow you full and legal control over the interface, at which time you
can put up anything you want.  In your case, the Notification Manager
would say something like "Whoa! My particular packet's here! Quick, open
up my cdev." 

Note that this is how the Print Monitor works.

> > Mike Moya

-- 
-----Nicholas Jackiw [jackiw@cs.swarthmore.edu|jackiw@swarthmr.bitnet]-----
"Here is how I built this artificial mine. I snatched a female louse from the
hair of humanity. I was seen to lie with her on three successive nights, and
then I flung her into the pit."       _Maldoror_, Canto II

topping@anaconda.cis.ohio-state.edu (brian e topping) (08/10/90)

In article <8JTNK0C@cs.swarthmore.edu> jackiw@cs.swarthmore.edu (Nick Jackiw) writes:
>
>moyman@ecn.purdue.edu (James M Moya) writes:
>> How is it that cdev/INIT's like Moire and SuperClock (and many others) can 
>> run in the background whether multifinder is running or not!!  I have been 
>> checking every mac bnook I know of to learn of this black magic...NOTHING.
>...  Instead, these programs install their code (usually into
>the system heap) while their INIT section is running.  Then, they alter
>the system environment somewhat so that their code gets called periodically.
>The two most popular ways of doing this are by patching a trap which you
>can count on all applications calling frequently (e. g. SystemTask) or
>which is relevant to your particular task (e. g. MenuSelect, if your
>init/cdev dynamically altered application menus), or by installing an
>interrupt handler which is invoked by the vertical blanking interval
>interrupt.  When either the trap is called or the VBL fires, the code
>they've loaded into the system heap is executed, allowing them to, say,
>check whether User's been idle for the predetermined time (Moire) or
>whether the clock has ticked (Superclock).

Actually, if you have ever looked inside what SuperClock, Pyro, and the like
are doing, you will have found a safer method.  I can never remember where
I saw this documented, but it is somewhere in the phone book edition
(the brown pages).  The trick is to use the low memory global jGNEFilter,
defined in the Apple assembler equates as:

    JGNEFilter	EQU 	$29A; GetNextEvent filter proc [pointer]

This is documented in Tech Note 85:

	You must call GetNextEvent periodically. GetNextEvent uses a
	filter (GNE filter) which allows for a routine to be installed
	which overrides (or augments) the behavior of the system. The
	GNE filter is installed by pointing the low-memory global
	jGNEFilter (a long word at $29A) to the routine. After all
	other GNE processing is complete, the routine will be called
	with A1 pointing to the event record and D0 containing the
	boolean result. The filter may then modify the event record or
	change the function result by altering the word on the stack at
	4(A7). This word will match D0 initially, of course.

The way the screen savers work is just watch the mouse location and reset
a counter to the new event->when value when it moves.  If 
(event->when - counter) goes past an amount of time (i.e. 360 for one minute)
the screen blanks.

This seems preferred over other methods because if the app isn't calling
WaitNextEvent, it probably is too busy to have cycles eaten up by screen
savers and the like.

>> > Mike Moya
>-----Nicholas Jackiw [jackiw@cs.swarthmore.edu|jackiw@swarthmr.bitnet]-----

Brian Topping
<topping@cis.ohio-state.edu>

llama@eleazar.dartmouth.edu (Joe Francis) (08/10/90)

In article <82899@tut.cis.ohio-state.edu> brian e topping <topping@cis.ohio-state.edu> writes:

->Actually, if you have ever looked inside what SuperClock, Pyro, and the like
->are doing, you will have found a safer method.  I can never remember where
->I saw this documented, but it is somewhere in the phone book edition
->(the brown pages).  The trick is to use the low memory global jGNEFilter,
->defined in the Apple assembler equates as:

->    JGNEFilter	EQU 	$29A; GetNextEvent filter proc [pointer]

->This seems preferred over other methods because if the app isn't calling
->WaitNextEvent, it probably is too busy to have cycles eaten up by screen
->savers and the like.

If you do this (and I don't recommend it), make sure that you call the
previous contents of the global (if they are not null), otherwise other
"lurkers" using this method will be high and dry.

----------------------------------------------------------------------------
"...beeeeeeep...This has been a test of the auto reboot system.  Had this
been a real system crash, the attention tone would be followed by loud
shrieks from distressed users..."

resnick@lees.cogsci.uiuc.edu (Pete Resnick) (08/11/90)

The method I have been using for getting something running in the
background is writing the code as a device driver that is in the
system heap and locked and the dNeedTime bit set. This seems much
safer than patching traps, and unlike VBL tasks (at least in THINK
C 4.0) you can have global variables floating around and call routines
that move memory. All the INIT does is call OpenDriver and exits.

pr
--
Pete Resnick             (...so what is a mojo, and why would one be rising?)
Graduate assistant - Philosophy Department, Gregory Hall, UIUC
System manager - Cognitive Science Group, Beckman Institute, UIUC
Internet/ARPAnet/EDUnet  : resnick@kant.cogsci.uiuc.edu
BITNET (if no other way) : FREE0285@UIUCVMD

zben@umd5.umd.edu (Ben Cranston) (08/11/90)

In article <1990Aug9.203803.13885@ecn.purdue.edu> moyman@ecn.purdue.edu
(James M Moya) writes:

> How is it that cdev/INIT's like Moire and SuperClock (and many others) can 
> run in the background whether multifinder is running or not!!   

Other followups to this message have mentioned Vertical Retrace interrupts
and patching traps, but there are two other solutions that might be useful
in some specific instances.

One possibility is to install a device driver at init time and use the
"needs periodic service" bit to get the driver called periodically as a
result of the user program calling SystemTask.   

Another possibility is to use IO completion chaining, in which the completion
routine for one IO operation does an ASYNCHRONOUS call to schedule IO for the
next IO operation.  For example, a simple AppleTalk responder could daisy
chain between a lurking read for a probe and a response to the probe.  Can
you say "responder"?  This works well when the parameter blocks can be
preallocated and mostly loaded and only a little information has to be patched
in on the fly.

-- 
Ben Cranston <zben@umd2.umd.edu>
A determined iconoclast, it would be better to assume the opinion expressed
above is the diametric OPPOSITE to that of the Warm and Fuzzy Network Group
of Egregious State University...

hawley@adobe.COM (Steve Hawley) (08/11/90)

In article <1990Aug9.203803.13885@ecn.purdue.edu> moyman@ecn.purdue.edu (James M Moya) writes:
>How is it that cdev/INIT's like Moire and SuperClock (and many others) can 
>run in the background whether multifinder is running or not!!  I have been 
>checking every mac bnook I know of to learn of this black magic...NOTHING.
>
>Exactly what is it they are doing?? Or does anybody *really* know...

I can't answer your question as to what they are doing, but I can tell you
a few ways that this can be done (although not in specifics).

First: you need to have your code running in the system heap so that it hangs
around no matter what application is running.

Second: You need some mechanism to have your function called periodically.
Here are a few ways to do this:
1) have your job submitted as a VBL task.  You can have it scheduled to run
   with a granularity down to 1/60th of a second.
2) Write a driver (file type DRVR, I think), which can also be accessed every
   so many clock ticks.
Both of these get called at the interrupt level, so you cannot execute any of
the 3 million toolbox functions that move memory.  This includes pretty much
everything useful (like drawing to the screen, but I'm sure someone like Tim
Maroney will correct me on this, since he has all the memory moving traps
memorized :').
3) Patch a common trap that gets called a lot (like GetNextEvent() or
   WaitNextEvent()).  This will not give you any control over granularity (in
   fact, you may NEVER get called), so you lose there.  Also, you will most
   certainly conflict with every other Mac program in the world which patches
   traps (since I understand, that is an in-vogue thing to do) and you will
   have a hairy time trying to support it (hint: if you make it big, you just
   blame compatability problems on everyone else's software, another in-vogue
   practice), but you can get at QuickDraw.

Conclusion:
Doable.  It ain't easy.  It's probably not fun, at least not my idea of fun.

Steve Hawley
hawley@adobe.com
-- 
"Break out the cameras that reshape my face and get someone to carve up my head"
        -Alcatraz, "God Blessed Video"

amanda@mermaid.intercon.com (Amanda Walker) (08/11/90)

In article <82899@tut.cis.ohio-state.edu>, topping@anaconda.cis.ohio-state.edu
(brian e topping) writes:
> The trick is to use the low memory global jGNEFilter

You can also write your code as a driver, and turn on the "needTime" bit,
which will cause your driver to be called when the application calls
SystemTask() or WaitNextEvent().  You don't need to patch anything, and
your cdev can talk to the driver code by doing PBControl() calls.

--
Amanda Walker <amanda@intercon.com>
InterCon Systems Corporation
--
"I've been with the best and the worst in my life, and the secret
 is they're all people."    -- Helen Drazenovich Berklich

stevec@Apple.COM (Steve Christensen) (08/11/90)

In article <23598@dartvax.Dartmouth.EDU> Joe Francis writes:
>In article <82899@tut.cis.ohio-state.edu> brian e topping writes:
>->Actually, if you have ever looked inside what SuperClock, Pyro, and the like
>->are doing, you will have found a safer method.  I can never remember where
>->I saw this documented, but it is somewhere in the phone book edition
>->(the brown pages).  The trick is to use the low memory global jGNEFilter,
>->defined in the Apple assembler equates as:
>
>->    JGNEFilter	EQU 	$29A; GetNextEvent filter proc [pointer]
>
>->This seems preferred over other methods because if the app isn't calling
>->WaitNextEvent, it probably is too busy to have cycles eaten up by screen
>->savers and the like.
>
>If you do this (and I don't recommend it), make sure that you call the
>previous contents of the global (if they are not null), otherwise other
>"lurkers" using this method will be high and dry.

jGNEFilter should never be nil since there is a default filterProc installed
before anyone else gets their fingers in.  The other important point is to
be sure to save A1 (and maybe D0) around your code since others down the
chain are expecting it to be setup...

steve

-- 
____________________________________________________________________

  Steve Christensen             Internet:   stevec@goofy.apple.com
  Apple Computer, Inc.          AppleLink:  STEVEC
  20525 Mariani Ave, MS 81-CS   CompuServe: 76174,1712
  Cupertino, CA  95014

  "You just contradicted me."  "No I didn't."
____________________________________________________________________

stevec@Apple.COM (Steve Christensen) (08/11/90)

In article <1990Aug10.175429.6092@ux1.cso.uiuc.edu> resnick@lees.cogsci.uiuc.edu (Pete Resnick) writes:
>The method I have been using for getting something running in the
>background is writing the code as a device driver that is in the
>system heap and locked and the dNeedTime bit set. This seems much
>safer than patching traps, and unlike VBL tasks (at least in THINK
>C 4.0) you can have global variables floating around and call routines
>that move memory. All the INIT does is call OpenDriver and exits.

Two of the problems about writing the code as a driver (when it doesn't need
to be) are that you tie up a space in the unit table (for code that does need
to be a driver), and that there may not be an opening for it in the unit table
(admittedly there usually is).  Patching traps is not as terrible as you
imagine as long as you take a little care in writing the code.  And both
trap patches and VBL tasks can have as global a variable as a driver can.
Which are really private variables since the applications own the global
data space...

steve

-- 
____________________________________________________________________

  Steve Christensen             Internet:   stevec@goofy.apple.com
  Apple Computer, Inc.          AppleLink:  STEVEC
  20525 Mariani Ave, MS 81-CS   CompuServe: 76174,1712
  Cupertino, CA  95014

  "You just contradicted me."  "No I didn't."
____________________________________________________________________

carlton@draco (Mike Carlton) (08/11/90)

In article <9694@goofy.Apple.COM> stevec@Apple.COM (Steve Christensen) writes:
+In article <23598@dartvax.Dartmouth.EDU> Joe Francis writes:
+>In article <82899@tut.cis.ohio-state.edu> brian e topping writes:
+>->Actually, if you have ever looked inside what SuperClock, Pyro, and the like
+>->are doing, you will have found a safer method.  I can never remember where
+>->I saw this documented, but it is somewhere in the phone book edition
+>->(the brown pages).  The trick is to use the low memory global jGNEFilter,
+>->defined in the Apple assembler equates as:
+>
+>->    JGNEFilter	EQU 	$29A; GetNextEvent filter proc [pointer]
+>
+>->This seems preferred over other methods because if the app isn't calling
+>->WaitNextEvent, it probably is too busy to have cycles eaten up by screen
+>->savers and the like.
+>
+>If you do this (and I don't recommend it), make sure that you call the
+>previous contents of the global (if they are not null), otherwise other
+>"lurkers" using this method will be high and dry.
+
+jGNEFilter should never be nil since there is a default filterProc installed
+before anyone else gets their fingers in.  The other important point is to
+be sure to save A1 (and maybe D0) around your code since others down the
+chain are expecting it to be setup...
+
+steve
+

Is using jGNEFilter safer or more dangerous than patching GetNextEvent?  I've
got an init which wants to steal some events.  Right now it patches GNE and
searchs the event queue and removes the one it wants.  I could instead 
use jGNEFilter and turn the event I want into a null event before it is 
returned.

Given that both methods would work for me, which is least likely to break
when new system software comes out (like, maybe 7.0 :)?  Is there any 
preference?

cheers,
Mike Carlton, UC Berkeley Computer Science	  	  	   	  ~
carlton@ernie.berkeley.edu    ...!ucbvax!ernie!carlton 		 	Manana

stevec@Apple.COM (Steve Christensen) (08/13/90)

In article <26932@pasteur.Berkeley.EDU> carlton@draco.berkeley.edu (Mike Carlton) writes:
>In article <9694@goofy.Apple.COM> stevec@Apple.COM (Steve Christensen) writes:
>+In article <23598@dartvax.Dartmouth.EDU> Joe Francis writes:
>+>In article <82899@tut.cis.ohio-state.edu> brian e topping writes:
>[...discussion of hooking into jGNEFilter to be called at GetNextEvent time]
>
>Is using jGNEFilter safer or more dangerous than patching GetNextEvent?  I've
>got an init which wants to steal some events.  Right now it patches GNE and
>searchs the event queue and removes the one it wants.  I could instead 
>use jGNEFilter and turn the event I want into a null event before it is 
>returned.
>
>Given that both methods would work for me, which is least likely to break
>when new system software comes out (like, maybe 7.0 :)?  Is there any 
>preference?

Well, I think either way would do.  SuperClock! uses jGNEFilter, and 7.0
hasn't broken it yet...  :-)

steve

-- 
____________________________________________________________________

  Steve Christensen             Internet:   stevec@goofy.apple.com
  Apple Computer, Inc.          AppleLink:  STEVEC
  20525 Mariani Ave, MS 81-CS   CompuServe: 76174,1712
  Cupertino, CA  95014

  "You just contradicted me."  "No I didn't."
____________________________________________________________________