[comp.sys.amiga] need info on exceptions

iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) (08/23/88)

[In "Re: Need info on exceptions", "Morgan W. Jones" said:]
>
> In article <1754@munsell.UUCP> jdj@munsell.UUCP (Joel Jennings) writes:
> >I am looking for a way to cause my program to take an exception periodically
> >so that it can write out intermediate results of a long calculation* (see
>
> One approach that seems reasonable would be to send a message to the
> timer.device asking it to send you a message in ten minutes (600 secs).
> Arrange that the reply port that it sends to generates a software
> interrupt of priority higher than your program (so that it preempts
> it), and this swi can delete the message, ask that another message
> be sent in ten minutes, and write out your intermediate data.  Of
> course, you'd have to make sure that a swi can do things like delete
> messages, send messages, open files, etc.
>
Unfortunately it can't.  "To avoid serious problems, the interrupt
routine must not use any of the memory allocation or deallocation
functions"--RKM.  That's apparently because critical system code
is surrounded by Forbid(), but not Disable().

That doesn't seem to leave much that interrupts can do.  Once again,
we're stuck with polling (and this on a multitasking OS).

iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) (08/23/88)

[In "Re: Need info on exceptions", Ronald G Minnich said:]
>
> In article <413@brambo.UUCP> morgan@brambo.UUCP (Morgan W. Jones) writes:
> >One approach that seems reasonable would be to send a message to the
> >timer.device asking it to send you a message in ten minutes (600 secs).
>    Hmm, we have a very nice OS here with a shared address space and
> named blocks of memory and lightweight tasks and ....
>    we are still thinking in terms of Unix.
>
> Or, maybe:
> Spawn a lightweight process (task is such a better word,
> but Mach kinda changed the meaning). Since it shares your
> context it *knows* where to look and how often to print.
> I am lying maybe since i have not done much with tasks.
> Can someone flesh this one out?
>
>    On unix you HAVE to have the signal cause sharing data in
> memory is so damn hard. On amiga sharing (even unintentional) is
> the easiest thing. Many processes can easily share an array. So
> why not do it, and save yourself the trouble of having signal
> handlers and such?
>
In principle, Tasks are not supposed to know about each other's memory
space.  In practice, the Manx geta4() function makes the globals
common.

I would think the "correct" way on the Amiga would be to send a
message to the Task with the address of the array to be accessed,
then wait for a reply.

Even if Tasks are directly sharing memory, they need to be synchronized
to avoid reading and writing data at the same time, so you do need
at least a signal.


--

Bill Kinnersley
  Physics Department            BITNET: iphwk@mtsunix1
  Montana State University      INTERNET: iphwk%mtsunix1.bitnet@cunyvm.cuny.edu
  Bozeman, MT 59717             CSNET: iphwk%mtsunix1.bitnet@relay.cs.net
  (406)994-3614                 UUCP: ...ucbvax!mtsunix1.bitnet!iphwk
"This message was packed as full as practicable by modern electronic
equipment.  Some settling of contents may have occurred during transmission."

rminnich@super.ORG (Ronald G Minnich) (08/24/88)

In article <3794@louie.udel.EDU> iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) writes:
>I would think the "correct" way on the Amiga would be to send a
>message to the Task with the address of the array to be accessed,
>then wait for a reply.
   Sure, that is ONE way. Point is, on the Amiga, there are LOTS of ways.
>Even if Tasks are directly sharing memory, they need to be synchronized
>to avoid reading and writing data at the same time, so you do need
>at least a signal.
   well, for some cases, yes you need synchronization. But for the 
specific case of having information available about the state 
of a computation, you absolutely do not. The reason is that
the variables related to 'doneness' of the computation are 
just simply going to get larger with time*. So what if you read 
the variable just before it gets increased? Your monitor process 
might be a little off, but such would be the case if the clock 
interrupt came in before the variable got increased. 
   Back to the question at hand. The signalling that the person 
was looking for was to allow a process to be interrupted and thus
get state information ('doneness' of the computation) out of  that
process. This sort of thing has been done for years and years on 
Unix and when you think about what is happening it is really a 
poor man's way of spawning a lightweight process that prints out 
state informatino and quits. In addition the parent blocks. And you 
have all this yucky overhead. On the amiga, on the other hand
(or on the Sequent with its microtasking library, or maybe
SunOS4 with its task library) you can have a compute task and 
an information task. You don't interrupt the computation to get
information about the computation, and you can get information 
at any time, not just when a clock strikes.
ron
* Let's see, can we see they are monotonically increasing? Sure, why not?

peter@sugar.uu.net (Peter da Silva) (08/24/88)

In article ... iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) writes:
> Unfortunately it can't.  "To avoid serious problems, the interrupt
> routine must not use any of the memory allocation or deallocation
> functions"--RKM.  That's apparently because critical system code
> is surrounded by Forbid(), but not Disable().

> That doesn't seem to leave much that interrupts can do.  Once again,
> we're stuck with polling (and this on a multitasking OS).

You shouldn't be doing much in an interrupt, on any system. These are real
hardware-type interrupts, you know. For software interrupts, you can
probably get away with doing memory hacking, since you know that the task
which posted them wasn't doing anything dangerous when it was posted. But,
really, you don't need to do anything like that, anyway... because you can
signal a sleeping task to do the actual grunt-work.

For this application, you should probably have the computation done with a
subtask which signals the sleeping main program at appropriate points in
the calculation.

dillon@CORY.BERKELEY.EDU (Matt Dillon) (08/25/88)

	Time to go into a brief description of the three types of interrupts
that exist on the Amiga:

(1) Task Exceptions (via SetExcept() and standard signals).  This is a
    task-level interrupt and only interrupts the task it is attached to. 
    Other tasks still run... the interrupt only interrupts the one task.  
    That is, any number of tasks may be handling exceptions all simultaniously.

    This is analogous to UNIX signals with one major exception.... system
    calls can get interrupted in the middle (i.e. library calls).  Although
    all run-time libraries are reentrant between tasks, this is not always
    so within a given task.  For instance, you cannot interrupt a DOS Write()
    with an exception and then do a Write() from within the exception!!
    Another for instance:  you CAN call AllocMem().

    So you have to be very careful as to when to allow an exception and when not
    to.  Forbid() effectively disables exceptions (but also task switching).
    Also, there is a bug in the exception handler in that if an exception
    occured during a Forbid() it does NOT execute when you Permit()... i.e.
    you also have to do a SetExcept(0,0) to force EXEC to check for active
    exceptions after you Permit().

    The 'simple' description of an exception is this:  First, a task gets
    signalled and if the exception bit for that signal bit is set, the
    EXCEPTION-ENABLE BIT AND THE SIGNAL BIT IS CLEARED and the task then enters 
    its exception handler.  D0 contains a mask of the exception that occured 
    (more than one bit may be set if more than one exception occured
    at once).  The exception handler thus must be reentrant for different 
    exception bits.  

    After the handler runs, it must return a bitmask in D0 of those exceptions
    that occured.  EXEC automatically ENABLES the exceptions specified by
    the bitmask.  However, it doesn't check to see if they re-occured at this
    time... Thus, there is a window of vulnerability here.  Usually, I
    reenable the exceptions manually with a SetExcept() call from the handler
    and return 0 in D0.  Unlike other types of interrupts, EXEC saves and
    restores ALL of our registers (except the stack pointer) for us.  But,
    you cannot make assumptions as to the contents of the registers (except
    for D0 and A1(=tc_ExceptData).  Specifically, there is no guarentee
    A4 will contain the small-code-model data segment base so you must reload
    it if you intend to use that model inside the handler.

(2) Software Interrupts.  Software interrupts are HIGHER priority than tasks
    but LOWER priority than interrupts.  Essentially, these are pseudo
    hardware interrupts but without the timing restrictions in real 
    interrupts.... you can do things that you would not want to do in normal
    interrupts because they would otherwise take too long.

    BUT!  A software interrupt is not a task, and you still may not use
    memory allocation/free functions within one (same restrictions as for
    hardware interrupts apply with the exception that you can take a longer
    time in the soft int).  For example, instead of calling ReplyMsg() from
    an HARD interrupt handler you might want to Cause() a softint instead.
    This allows the HARD int to end (and other HARD ints to occur).

    A software interrupt uses the same structure as a hardware interrupt.

(3) Hardware Interrupts.  Real honest to goodness hardware interrupts.  
    Implemented by SetIntVector() and AddIntServer() and the like.  These
    are real hardware interrupts and the service routine should take as
    little time as possible in them... I mean as *little* time as possible.
    Make your code tight.  Calling something like ReplyMsg() or PutMsg(),
    while it works, usually takes too much time for an interrupt handler
    to spare.  Cause() a softint for things that take too much time so
    other interrupts can go.  I don't know how much time Signal() takes.

    There are two flavors.  (1) Direct hardware interrupts (SetIntVector()),
    and (2) Chained hardware interrupts.  In many cases there are also
    resources (misc.resource, for instance) to arbitrate usage of some of
    the interrupt vectors.

					-Matt


:In article ... iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) writes:
:> Unfortunately it can't.  "To avoid serious problems, the interrupt
:> routine must not use any of the memory allocation or deallocation
:> functions"--RKM.  That's apparently because critical system code
:> is surrounded by Forbid(), but not Disable().
:
:> That doesn't seem to leave much that interrupts can do.  Once again,

:> we're stuck with polling (and this on a multitasking OS).
:
:You shouldn't be doing much in an interrupt, on any system. These are real
:hardware-type interrupts, you know. For software interrupts, you can
:probably get away with doing memory hacking, since you know that the task
:which posted them wasn't doing anything dangerous when it was posted. But,
:really, you don't need to do anything like that, anyway... because you can
:signal a sleeping task to do the actual grunt-work.

morgan@brambo.UUCP (Morgan W. Jones) (08/26/88)

In article <3793@louie.udel.EDU> iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) writes:
>[In "Re: Need info on exceptions", "Morgan W. Jones" said:]
>> course, you'd have to make sure that a swi can do things like delete
>> messages, send messages, open files, etc.
>Unfortunately it can't.  "To avoid serious problems, the interrupt
>routine must not use any of the memory allocation or deallocation
>functions"--RKM.  That's apparently because critical system code
>is surrounded by Forbid(), but not Disable().

I'm not so sure.  True, if you are dealing with "real", harware
generated interrupts you run into this problem.  Software interrupts,
however, are generated by the operating system.  Thus, it seems that
it would be impossible to destroy kernel data from inside a software
interrupt - they should all be valid.  Software interrupts are
actually recommended in the RKM for use when you want to do a lot of
processing inside an interrupt so that the system doesn't slow down -
this implies that the system multi-tasks during software interrupts
and so the software interrupt should appear as a task to the O/S.

Any Gurus want to comment on this?

-- 
Morgan Jones                                 morgan@hcr.UUCP
Human Computing Resources, Toronto, Canada
"BMATH - 8 months and counting ..."

dillon@CORY.BERKELEY.EDU (Matt Dillon) (08/28/88)

:generated interrupts you run into this problem.  Software interrupts,
:however, are generated by the operating system.  Thus, it seems that
:it would be impossible to destroy kernel data from inside a software
:interrupt - they should all be valid.  Software interrupts are
:actually recommended in the RKM for use when you want to do a lot of
:processing inside an interrupt so that the system doesn't slow down -
:this implies that the system multi-tasks during software interrupts
:and so the software interrupt should appear as a task to the O/S.
:
:Any Gurus want to comment on this?

	Yes I would.  You are dead wrong.  Sorry.

	SOFTWARE INTERRUPTS ARE JUST LIKE HARDWARE INTERRUPTS!  The only
difference is that normal hardware interrupts can occur while one is processing
a software interrupt.  The system does not multi-task while one is processing
a software interrupt.  Neither can you AllocMem() inside a software interrupt.
same rules apply as for hardware interrupts.

				-Matt

iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) (08/29/88)

[In "Re: Need info on exceptions", Ronald G Minnich said:]
:
: In article <414@brambo.UUCP> morgan@brambo.UUCP (Morgan W. Jones) writes:
: >Somebody forgot their Operating Systems course, eh?
: >The problem with all of these approaches, of course, is that you've
: >got two processes reading the same data at the same time, or, more
: >specifically, one reading the data while the other is still writing.
: Seems like you might need to actually use this sort of system
: for a while before you understand it. I can't see why this is
: so hard for people to get.
: No, this is NOT A PROBLEM. You have a single writer, single reader.
: The variable relating to DONENESS will INCREASE SLOWLY AS THE
: COMPUTATION PROCEEDS. YOU CAN LOOK AT IT AT ANY TIME!
: PEOPLE DO THIS SORT OF THING ALL THE TIME!!! AMAZING, HUH?
: The writer is the compute process. the reader is the 'front panel'.
: Think a little bit before you comment. Or get a little experience
: with this sort of thing before you comment. Or don't comment.
: Seems that your level of knowledge does not extend much PAST
: an operating systems course!
: Or, try again,
:         NO, YOU DON'T NEED SEMAPHORES FOR THIS PROBLEM!!!!
: Get it?
: ron
:
Seems to me it depends on what you're computing, Ron.  You're right if
it's just one variable.

Suppose one task is updating a chess board and the other task is printing
it out.  The printer may start up just as a piece has been moved to
a new square, but not yet erased from the previous one.

In general, the data set may pass through inconsistent states, and a
semaphore is a way of preventing this problem.


--Bill K.

mlelstv@faui44.informatik.uni-erlangen.de (Michael van Elst ) (08/29/88)

In article <3793@louie.udel.EDU> iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) writes:
>[In "Re: Need info on exceptions", "Morgan W. Jones" said:]
>>
>> In article <1754@munsell.UUCP> jdj@munsell.UUCP (Joel Jennings) writes:
>> >I am looking for a way to cause my program to take an exception periodically
>> >so that it can write out intermediate results of a long calculation* (see
>>
>> ... asks about software interrupts from the timer.device ...
>>
>Unfortunately it can't.  "To avoid serious problems, the interrupt
>routine must not use any of the memory allocation or deallocation
>functions"--RKM.  That's apparently because critical system code
>is surrounded by Forbid(), but not Disable().
>
>That doesn't seem to leave much that interrupts can do.  Once again,
>we're stuck with polling (and this on a multitasking OS).

Hello,

I don't think that you have to poll for this. There are two approaches
to this problem.

If your program is designed as an event loop (i.e. a loop Wait()ing
for messages and then working on each of them) you can easily send a
request to the timer.device to wake you up. When the timer replies your
request you can write out your intermediate results and post another
request to the timer.
Thereis a problem if you have to Wait() at another point in your program
(likewise a DOS call, that Wait()s internally for IO to complete).
You MUST disable any verify IDCMP messages for intuition is locked until
you reply. If then a requester wants to apear ("Please insert...")
you get a deadlock situation.
You might disable other event sources (i.e. menus) if handling an event
lasts for a longer time. Otherwise input events might be allocated
at your message port and might not be freed until your program ends.

If your program cannot be designed as an event loop (in this case it
seems to be so for you want to calculate something) you may spawn
another process that deals with the DOS and that is woken up by
the timer.device. The problem there is to get a real 'Process' because
you have to call DOS routines, a simple 'Task' cannot do this.
The only legal way to create a process is to call the DOS function
CreateProc but it uses a structure called SegList. Therefore
you have to LoadSeg() your updating process and to communicate with it
to get pointers to your first process' memory. Or you have to construct
your own SegList but I haven't found a method to do this from C.
(I think Lattice C can do it but I am not sure)
A simpler method to get around the need for a process is to construct
your main program as an event loop and spawning a 'Task' to do
your calculations. To display your calculations (if it is for example
a Mandelbrot set or a raytracing picture) you then can send messages
to your main process to indicate that a part of the calculation can
be used.
The task model is sufficient for most applications for you hardly need
two or more processes twiddling with DOS. And even this could be done
by a single process using asynchronous IO (i.e. sending DOS packets
instead of calling DOS functions).

Enough said.


				Michael van Elst

E-mail: UUCP: ...seismo!unido!fauern!faui44!mlelstv
E-mail: UUCP: ...uunet!unido!fauern!faui44!mlelstv	<- when seismo ceases
							   operation

rminnich@super.ORG (Ronald G Minnich) (08/29/88)

In article <3867@louie.udel.EDU> iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) writes:
>Seems to me it depends on what you're computing, Ron.  You're right if
>it's just one variable.
Yes, true if it is one variable you are ok. If it is not, then you
need semaphores. The original question, as i understood it, was
to monitor the progress of a computation, which i assumed would be
indicated by one variable. A proposed way was to use the amiga
equivalent of signal(), since "that's how it was done on Unix".
   I feel very strongly that if you can avoid 
it then don't use interrupts, software or hardware. They are an 
invitation to trouble, and besides, there are much much much better
ways to solve some of these problems on the amiga. 
   I mean, geez, you just do an ObtainSemaphore and a ReleaseSemaphore
and there is one to poll a Semaphore. What more could you ask? 
And they work. 
   Take a look at how people use signals and longjmp() and things on 
Unix. In many cases it is really gross, but there is no other way
because most Unix systems do not even support mmap(), much less 
a simple system such as shmget(). And the way shmem() 
works is real gross. But on the
amiga we can share memory just by sending each other messages. That is 
a wonderful capability. 
   A few years ago an unnamed person at an unnamed company wrote a 
system for IPC that used a high-speed network being developed at Udel.
That network presented hosts with the shared-memory model. The ipc
system allowed you to send messages that contained memory handles.
When i explained that the Amiga IPC already did all this stuff, and
that the network hardware would do well on an amiga, i mostly got
blank stares ("put a network on a game machine?..."). But the 
fact remains that the amiga IPC is well designed and sophisticated,
and well worth using as a way to share memory between several tasks-
something not easily done on Unix. 
ron

BEB%UNO.BITNET@cunyvm.cuny.edu (08/30/88)

Getting back to the original posting for a second: (not that all this stuff
on exceptions and tasking and critical sections wasn't real interesting)
I would like to know:

Is this application an essentially iterative process? If so, why not just
pick some arbitrary number of iterations to count, then checkpoint? If the
e.t. of the iterations is non-linear, than how about some similar non-linear
decrease in iterations between checkpoints? The advantage here is you avoid
the overhead and complexity  of multiple tasks and the synchronization thereof,
and you don't have to worry about invalid data.

                                  Bruce
death before disclaimer
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
<>Handle:   Bruce Bettis         USnail:   University of New Orleans  <>
<>BITnet:   <BEB@UNO.BITNET>               Computer Research Center   <>
<>Voices:   (504) 286-7067                 New Orleans, La. 70148     <>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

koster@cory.Berkeley.EDU (David Ashley) (08/30/88)

Really getting back to the first question, what would be a good idea is
trying to find out why the #1 task bombs in the first place. Rather than
work around the bombing, trying to save the state of the system, fix the
problem.