Amiga.org

Operating System Specific Discussions => Amiga OS => Amiga OS -- Development => Topic started by: Jose on May 26, 2006, 07:45:33 PM

Title: Exec exception handling and a time interval implementation...
Post by: Jose on May 26, 2006, 07:45:33 PM
I have almost finishing implementing in my program something more or less general that allows any kind thing (code or data) to change through time according to user specified intervals and intervalsets (sets of subsequent intervals). As allways, rather than going for the easy way I want to tweak it and make the design the more efficient possible:) Currently I'm undecided between the following 3 ways and have one important doubt in 1:
1- Having the timer.device send messages when the beggining of next interval is reached to the process that handles the object, the messages being handled by an Exec exception. This is my favourite but I'm having a problem with it: I've read that Exec disables signals while processing exceptions, so what will happend if another signal is received (e.g. signaling the end of another objects current interval) while the exception is being processed, will exec process it after ?
2- Same as above but through a software interrupt, although here all other processes will be interrupted to process it so probably not as good.
3- Screw it, it's not that much big overhead in general except when time intervals are very short so check to see if current interval time has already passed each time the corresponding object is used, while in previous implementations it would only need to copy a pointer to the object before starting to use it. Not so efficient of course, cause it's done each time the object is used but less implementation headaches.

What do you guys think ?
:pint:
Title: Re: Exec exception handling and a time interval implementation...
Post by: itix on May 26, 2006, 09:41:25 PM
1) Exceptions are not safe. They can interrupt your program flow at critical point.

2) You cant do much from interrupts. Most system calls are big no no.
Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on May 26, 2006, 11:33:46 PM
Quote
2- Same as above but through a software interrupt, although here all other processes will be interrupted to process it so probably not as good.

This is my favorite.

You could also use the undocumented msgport feature: Setting mp_Flags to 3 will call routine in mp_SigTask when message arrives to msgport. System is in Disable(), and A6 points to execbase, A1 to the msgport in question (making assumptations about other registers is unwise). This is direct call from the context of the thing generating the signal (PutMsg() or ReplyMsg() call in 99% of cases).
Title: Re: Exec exception handling and a time interval implementation...
Post by: Jose on May 27, 2006, 06:25:02 PM
@itix

The RKM's say timer.device is safe to use.

@Piru

"This is my favorite."
Why ?:-) If intervals get very short the other tasks running will come to an halt, or not ? Using 1 the time precision would be limited by the speed of the system and other running tasks but processor time would be evenly distributed among them according to their priority.

"You could also use the undocumented msgport feature:
Setting mp_Flags to 3 will".

The RKM Libs (what I've read) talks about it. It's the PA_SOFTINT flag.
Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on May 27, 2006, 07:14:49 PM
Quote
The RKM's say timer.device is safe to use.

timer.device is, but exec exceptions are not.

Quote

"This is my favorite."
Why ?

It's well documented and easy to use. If you just SendIO() the timer ioreq again in the softint code it will create a nice loop.

Quote
If intervals get very short the other tasks running will come to an halt, or not ?

Yes. If you're worried about this use regular timer loop or so. Even that will trigger rescheduling a lot so that'll be quite slow aswell (but not as slow as softint flood, true).

Quote

"You could also use the undocumented msgport feature:
Setting mp_Flags to 3 will".

The RKM Libs (what I've read) talks about it.

No they don't. This feature is undocumented.

Quote
It's the PA_SOFTINT flag.
Code: [Select]
#define PA_SOFTINT  1

Title: Re: Exec exception handling and a time interval implementation...
Post by: Jose on May 29, 2006, 07:58:39 PM
Sounds cool. So that means using mp_Flags set to 3 the called routine in mp_SigTask won't use the system stack and supervisor mode right ? Wich means it will be faster. But in this case won't the context be the timer.device's (that's sending a ReplyMsg() to my timerequests) ? Is that even a good thing (using timer.device's context) ?
Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on May 29, 2006, 08:03:08 PM
Well, it's fast, but indeed it has some problems. For timer.device it indeed gets called from interrupt, IIRC.
Title: Re: Exec exception handling and a time interval implementation...
Post by: Jose on June 01, 2006, 07:23:08 PM
One more question 8-)
Is the Disable state entered right away when message is sent or replied (like in an interrupt)or only after that Exec's round robin thing reaches the corresponding task ?
Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on June 01, 2006, 08:26:47 PM
Uh. If task has done Forbid() or Disable() there won't be any rescheduling.

Of course it is instant.
Title: Re: Exec exception handling and a time interval implementation...
Post by: tboeckel on June 08, 2006, 10:34:09 PM
Quote
You could also use the undocumented msgport feature


Do you really think this is a wise decision? If it is not documented then there is a reason why it is not. Even if it may work now with one specific version of AmigaOS, nobody can give you a guarantee that it will work for all times.

Hacking like this makes further development of AmigaOS so extremly hard. Just because some very clever programmers think they are smarter than others exactly this kind of program will crash and burn in the future. One should have learned that lesson from history (OS1.x -> OS2.x, OS2.x -> OS3.x, etc)

Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on June 08, 2006, 11:02:35 PM
@tboeckel
Quote
Do you really think this is a wise decision?

Probably not. I just presented it as an option, with obvious caveat about it being undocumented.

Quote
Hacking like this makes further development of AmigaOS so extremly hard.

It does? I haven't noticed any problems here.

Quote
Just because some very clever programmers think they are smarter than others exactly this kind of program will crash and burn in the future. One should have learned that lesson from history (OS1.x -> OS2.x, OS2.x -> OS3.x, etc)

Well, clealy any OS that breaks backwards compatibility in such a way sucks donkey b***s.

PS. All AmigaOS versions at least from 1.x to 3.9 support this mp_Flags = 3 trick. MorphOS supports it aswell.

BTW:
Code: [Select]
---------------------------------------------------------------------------
  PutMsg( port, message )
          A0    A1
---------------------------------------------------------------------------

FC1B34  move.b    #5,8(A1)          Make sure message node type is NT_MESSAGE
FC1B3A  move.l    A0,D1
FC1B3C  lea       $14(A0),A0        Compute address of port's message list

FC1B40  move.w    #$4000,DFF09A     Disable()
FC1B48  addq.b    #1,$0126(A6)

        ; Enqueue the message at the end of the port's message list

FC1B4C  lea       4(A0),A0          Point A0 at port's Tail field.
FC1B50  move.l    4(A0),D0          Save pointer to last node in list
FC1B54  move.l    A1,4(A0)          Make new node the last node
FC1B58  move.l    A0,(A1)           New node has no next node
FC1B5A  move.l    D0,4(A1)          Link new node back to old last node
FC1B5E  move.l    D0,A0
FC1B60  move.l    A1,(A0)           Link old last node to new node

        ; Do whatever needs to be done on message arrival.

FC1B62  move.l    D1,A1
FC1B64  move.l    $10(A1),D1        Get address of message port's task.
FC1B68  beq.s     FC1B9E            Exit if port has no task.

FC1B6A  move.b    $0E(A1),D0        Get port's flag bits.
FC1B6E  and.w     #3,D0
FC1B72  beq.s     FC1B8E            Decode the flag bits.
FC1B74  cmp.b     #1,D0
FC1B78  bne.s     FC1B82

        ; Processing for PA_SOFTINT

FC1B7A  move.l    D1,A1
FC1B7C  jsr       -$B4(A6)          Cause the software interrupt.
FC1B80  bra.s     FC1B9E

        ; If PA_IGNORE, do nothing.

FC1B82  cmp.b     #2,D0
FC1B86  beq.s     FC1B9E

        ; (Undocumented?) processing for mp_Flags = 3.  Apparently,
        ; calls a subroutine at mp_SigTask.

FC1B88  move.l    D1,A0
FC1B8A  jsr       (A0)
FC1B8C  bra.s     FC1B9E

        ; Processing for PA_SIGNAL

FC1B8E  move.b    $0F(A1),D0        Get SigBit.
FC1B92  move.l    D1,A1
FC1B94  moveq     #0,D1             Compute corresponding signal mask.
FC1B96  bset      D0,D1
FC1B98  move.l    D1,D0
FC1B9A  jsr       -$0144(A6)        Signal the task.

FC1B9E  subq.b    #1,$0126(A6)      Enable()
FC1BA2  bge.s     FC1BAC
FC1BA4  move.w    #$C000,DFF09A
FC1BAC  rts      

from dev/asm/ExecDis.lha (http://www.aminet.net/package.php?package=dev/asm/ExecDis.lha)

Thus, this mp_Flags 3 trick has been common knowlege at least from february 1989, that's for 17 years.
Title: Re: Exec exception handling and a time interval implementation...
Post by: tboeckel on June 09, 2006, 05:53:55 AM
Quote
All AmigaOS versions at least from 1.x to 3.9 support this mp_Flags = 3 trick. MorphOS supports it aswell.


I know that argument too well. A very similar discussion was held about if and where AllocVec() stores the size of an allocation. Some very clever people are really convinced that the size must always be stored in a ULONG before the returned address. This was never documented and the fact that it was done that way upto OS3.9 made some programs crash when OS4 beta introduced its new memory system. This system doesn't need to store such a size at all, and hence all assumptions were bogus.

Ok, you might try to tell me to keep up this behaviour even with the new system. But why? No Autodoc ever stated that AllocVec() would store the size anywhere, and if it did, nobody could tell where. The fact that the size was stored directly in front of the allocation was discovered by reverse engineering, hacking, very clever people or whatever. And from that point on it was considered as "almost documented" and some programs relied on this "fact". Even one well known text editor exploited this undocumented feature and therefore crashed instantly.

What I want to say is: NEVER rely on undocumented features. These are things that may change at any time, and sooner or later this change will happen!

But what about making this mp_Signal=3 thing official? I will put a question on the OS4 beta list.
Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on June 09, 2006, 08:26:51 AM
Quote
I know that argument too well. A very similar discussion was held about if and where AllocVec() stores the size of an allocation. Some very clever people are really convinced that the size must always be stored in a ULONG before the returned address. This was never documented and the fact that it was done that way upto OS3.9 made some programs crash when OS4 beta introduced its new memory system. This system doesn't need to store such a size at all, and hence all assumptions were bogus.

Well, I guess this is why MorphOS has better compatibility than OS4.

In MorphOS we don't break compatibility (even undocumented!) unless if it's absolutely needed. AllocVec stores the size as ULONG before the actual allocation, dos.library MatchPattern[NoCase] return value was not changed just because of "cleanup" and so on.

Just because MorphOS has a new highly optimized memory system, it doesn't break such undocumented things.

Quote
Ok, you might try to tell me to keep up this behaviour even with the new system. But why?

OK, supporting "undocumented" return values or features might seem silly, but IMO if supporting them is much more sensible than breaking them for no good reason. All these supported undocumented features add up to much greater software compatibility.

Quote
What I want to say is: NEVER rely on undocumented features.

I agree. But unfortunately this doesn't help with already existing applications that rely on these undocumented features (there are tons of apps that you can't fix/recompile). Thus, to get the best possible experience out of your OS, you need to support these things.

Sure, you're free to disagree, but this is what I think and try to maintain in my MorphOS work.

Quote
But what about making this mp_Signal=3 thing official?

Well, do what you like, I consider it official already.
Title: Re: Exec exception handling and a time interval implementation...
Post by: tboeckel on June 09, 2006, 09:02:22 AM
Quote
In MorphOS we don't break compatibility (even undocumented!) unless if it's absolutely needed. AllocVec stores the size as ULONG before the actual allocation, dos.library MatchPattern[NoCase] return value was not changed just because of "cleanup" and so on.


So far it was only one application (GoldED) that failed badly with OS4's new memory system. Dietmar fixed this issue already, but in the beginning he was also refusing to accept the fact that any internal workings of AllocVec() were undocumented from the beginning. As a result AllocVec()'s old behaviour was kept up for 68k code, but dropped for PPC code (AFAIK), just to avoid future usage of such hacks.

That is only one very prominent example where it was easy to distinguish between old and new software. But that is not always possible. And if it breaks only some ancient software I prefer a cleaned up system with enforced adherence to the documented facts.

Quote
Quote
Ok, you might try to tell me to keep up this behaviour even with the new system. But why?

OK, supporting "undocumented" return values or features might seem silly, but IMO if supporting them is much more sensible than breaking them for no good reason. All these supported undocumented features add up to much greater software compatibility.


Maintaining backward compatibility is a good thing, as long as you don't encourage the usage of illegal exploits, like that AllocVec() thingy. If you don't put a stopper to such illegal behaviour people will continue to use it for all times, just because one clever person told them it works that way. And then you have to carry around tons of legacy code, just to support one ancient application which did things wrong from the beginning. And to carry on with these bugs because they never caused any problems so far is very stupid IMHO.

Quote
Quote
What I want to say is: NEVER rely on undocumented features. These are things that may change at any time, and sooner or later this change will happen!

I agree. But unfortunately this doesn't help with already existing applications that rely on these undocumented features (there are tons of apps that you can't fix/recompile). Thus, to get the best possible experience out of your OS, you need to support these things.

Sure, you're free to disagree, but this is what I think and try to maintain in my MorphOS work.


Keeping up compatability is a good thing. But you shouldn't encourage usage of things like mp_Flags=3. This was also completely new to me. If you know it, it's ok. You know about the limitations and dangers. But others don't know about it and nobody can read about that anywhere, because it is undocumented. Hence, better keep it secret.
Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on June 09, 2006, 09:15:37 AM
Quote
As a result AllocVec()'s old behaviour was kept up for 68k code, but dropped for PPC code (AFAIK), just to avoid future usage of such hacks.

So you have asymmetrical system where PPC and 68k routines work in a different way? How is that "cleaned up"? I really wonder if it really was worth the trouble to change this behaviour in the end. Wouldn't it have been much more sensible to just keep the size in there? (I mean not being able to predict problems with this change is just incompetent).

Quote
That is only one very prominent example where it was easy to distinguish between old and new software. But that is not always possible. And if it breaks only some ancient software I prefer a cleaned up system with enforced adherence to the documented facts.

Well, that's the problem: You don't know what breaks (you never can test every application). There is no way of knowing what important and cool applications will break.

I can accept less cleaned up system if it works better with old applications.

Quote
But you shouldn't encourage usage of things like mp_Flags=3. This was also completely new to me.

Well, I see no problem in telling people about it. This way they will know about it, at least. Just telling about it doesn't mean you're encouraging use of it.

Quote
You know about the limitations and dangers. But others don't know about it and nobody can read about that anywhere, because it is undocumented.

That's why I explained in detail the limitations and usage.

Quote
Hence, better keep it secret.

I disagree. Better know about these things, at least then future OS coders won't break the compatibility for no reason.
Title: Re: Exec exception handling and a time interval implementation...
Post by: RWO on June 09, 2006, 10:41:01 AM
@Piru

Whouldent you get in trouble if a 68k application used that tick and ended up is a PPC code function.

I can imagine that the Emulator jumping from a 68k function to another 68k function, but crossing over whould lead into trouble.

RWO
Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on June 09, 2006, 11:05:48 AM
@RWO
Quote
Whouldent you get in trouble if a 68k application used that tick and ended up is a PPC code function.

No.

Quote
I can imagine that the Emulator jumping from a 68k function to another 68k function, but crossing over whould lead into trouble.

It does not. The code is always executed as 68k. If a PPC function is to be called, there needs to be a gate:
Code: [Select]

#include <emul/emulregs.h>
#include <emul/emulinterface.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <clib/debug_protos.h>

void func(void)
{
  struct MsgPort *port    = (APTR) REG_A1;
  struct Library *SysBase = (APTR) REG_A6;
  kprintf(&quot;SysBase 0x%lx port 0x%lx\n&quot;, SysBase, port);
}

static const struct EmulLibEntry GATEfunc =
{
  TRAP_LIBNR, 0, func
};

...

mp->mp_Node.ln_Type = NT_MSGPORT;
mp->mp_Flags = 3;
mp->mp_SigTask = (APTR) &GATEfunc;
NEWLIST(&mp->mp_MsgList);


And no, it doesn't go thru m68k emulation there. MorphOS is smart enough to spot PPC->m68k->PPC call and skip over the emulation completely. So it's a direct PPC->PPC call in the end, with no performance penalty. This is the whole point of MOS: Have the old API while giving full PPC performance benefits for both old and new apps. Old m68k apps automagically benefit from native libraries, while new PPC apps can continue to use the same API, without performance losses. Naturally you can also create fully PPC native APIs if you wish.
Title: Re: Exec exception handling and a time interval implementation...
Post by: RWO on June 09, 2006, 12:06:20 PM
@Piru

Yes I can understad that adding a Trap function in the mp_SigTask will work but I were thinking more in the lines like we have an old program 68k and an old system 68k.. now as time go by the system get upgraded to PPC, then the old program still has a direct address and not a Trap.. in that case I se it fail.

RWO
Title: Re: Exec exception handling and a time interval implementation...
Post by: Piru on June 09, 2006, 12:15:48 PM
@RWO
Quote
we have an old program 68k and an old system 68k.. now as time go by the system get upgraded to PPC, then the old program still has a direct address and not a Trap.. in that case I se it fail.

Err, no. It won't. Naturally the OS still calls the routine as m68k one.

If there is any OS that will fail in that case, then the OS in question is broken beyond repair. You just can't change the way these things work.
Title: Re: Exec exception handling and a time interval implementation...
Post by: itix on June 09, 2006, 02:01:36 PM
Quote

Yes I can understad that adding a Trap function in the mp_SigTask will work but I were thinking more in the lines like we have an old program 68k and an old system 68k.. now as time go by the system get upgraded to PPC, then the old program still has a direct address and not a Trap.. in that case I se it fail.


Trap instruction (0xff00 family instructions) is not needed for 68k code. It just only indicates start of PPC code and when there is not trap the stuff is executed in 68k emulation mode.

68k function pointer in the mp_SigTask is not different than 68k function pointer in the h_Entry of struct Hook for example.