problem about share interrupt

Even if I disagree on what is the correct behaviour, this thread needs remembered because the issue is far from intuitive and shows up how attention needs to be paid to IRQ selection.

Leading to the question; If this is so prevalent, why doesn’t the BIOS have more options to control device location? Or, is this something the OS is ment to handle?

cdm: I wasn’t saying QNX only. Just that, with cooperation, sharing can be managed in a deterministic way.

If you are sharing interrupt on 2 devices under your control, and writing ISR for both of them by your own,
and be able to make each ISR quick enough to a) identify the interrupt source, b) do whatever necessary
in ISR, and c) unmask the interrupt… then you can probably still manage “deteministic behavor”.

Or do I miss anything ?

Even if you have control of both drivers, this doesn’t change the fact that since you are sharing the IRQ line you cannot assign different priorities to the different drivers. Let’s say you have a watchdog timer, that must be serviced in a short time period (say 500 usec), and a GigE NIC, and that you are sharing interrupts between these 2 devices. In this case, the watchdog timers max latency is at the mercy of the GigE drivers worst case latency.

In this case InterruptAttachEvent doesn’t bring you any relief in the form of schedulability, since the scheduling event is the same (the shared IRQ).

Dissing InterruptAttachEvent is completely inappropriate, since it at least offers the potential of schedulability if the hardware allows it (i.e. there are differing scheduling events available).

With InterruptAttach, even if you have different scheduling events (aka IRQs) then you still don’t have control of schedulability (outside of hardware interrupt priorities - which on PCs, are very limited).

The bottom line is:

  1. InterruptAttachEvent (or InterruptWait in a thread with an assigned priority) is good.

  2. Undifferentiated scheduling events (shared IRQs) are bad.

The fact that InterruptAttachEvent does not mitigate the problems associated with #2 is not a failing of InterruptAttachEvent.

xtang:
You are completely correct. With cooperation, namely a timely unmasking, there is no conflict.

But as rgallen is pointing out, and as I have learnt, this mindset conflicts with InterruptAttachEvent() by that very requirement. One of the very reasons for InterruptAttachEvent() is to allow delayed processing of an interrupt.

So, sharing is deemed undeterministic and IRQ routing needs managed to make room for fast response IRQs.

Basically, if you have 2 different types of interrupt coming in (GigE and a Watchdog were mentioned) and the handling of one exceeds the allowable delay requirement for the other, the first must poll the second from within the handler frequently enough to address the requirement. You can do that (maybe) if you control both handlers, but as long as the interrupt is masked you must poll.

One alternative is a second level of handler which is a complexity not to be lightly undertaken. The interrupt is handled by “dispatcher” which identifies the source and unmasks almost instantly IF IT CAN STOP THE SOURCE ON THE CHIPSET INVOLVED. It sends a secondary signal to to start a thread that handles the interrupt source at an appropriate priority. This means that the GigE thread would not be handled at an INTERRUPT priority it would have its own, and it could be interrupted by the watchdog which would have ITS own priority, presumably higher. The cost is another level of micro-delay in getting to the real service routine and the complexity of turning off an interrupt line at the chip level every time you see an interrupt from the chip. Polling can be faster and heaps simpler.

If this is not possible you must separate the two.

The lack of control over the interrupt assignments is a choice of the bios designers of the PC world. There have been bios designs which allowed assignment of interrupts to slots. The automation of this process has robbed us of some of the tools for Real-Time and it is conceivable that we as a community should ask for a bios version that gives us back that level of contol from AMI or Phoenix or whomever. It would not, I think, be too difficult to do, but the people who should be asking for this are the SBC manufacturers.

The number of interrupts on the PC is limited by the chips used. That is also a standardization issue of the PC world. A few more wouldn’t hurt :slight_smile:

respectfully
BJ

Only by violating one of the fundamental rules of software engineering (don’t couple separate components).

This can be done using InterruptAttach (a “one liner” handler that disables the source and dispatches an event), but this is not a general solution, and will only work with devices that have a short code path to disable the source (network cards under high load - like a GigE NIC for instance - often go into a loop for very long periods of time, in order to assure that all sources are cleared before exiting. It is important to note, that this behavior, can be adequately dealt with in a real-time system when using InterruptAttachEvent and unique IRQs.

Again, this implies hardware behavior that simply cannot be assumed by an OS vendor.

QNX already has the second layer (i.e. an interrupt dispatcher), and I haven’t seen complaints about interrupt dispatch latency.

In the real world, and certainly for a company providing a RTOS, it can never be considered possible, since it hardly ever is possible; hence the “don’t share” IRQs rule-of-thumb…

Yup, but I bet if money is no object you can get hardware that does exactly what you want. Like Joe Walsh once said “I can’t complain, but sometimes I still do” :slight_smile:

And both of those options require unknown drivers to be modified, that’s not quite what I had in mind. If I was going down that path I’d be asking for the OS to be modified. ;)

No, InterruptAttachEvent() is a good thing and non-deterministic sharing is a price I’m prepared to accept.

xtang listed the only viable deterministic IRQ sharing method. And that requires all drivers on a specific IRQ to be using InterruptAttach().

I withdrew from this thread to try to get a better point of view of this whole issue, instead of getting caught up in it.

First I’d like to comment on the use of the word deterministic and real-time. Their meaning is somewhat vague, lack clarity and often introduces misunderstanding during discussion like this. I get shiver when I hear the word deterministic as it was used in this thread. First time I heard that word, the context was an OS were the number of CPU cyles for each an every function call was specified. Today with complexity of CPU that close to impossible.

In my book QNX 4/6 are very very “soft deterministic”. It’s impossible to estimate how long an operation will take hell I can’t tell if some of the OS software are disabling interrupts at time. Best I can do is create a design that makes as little assumption as possible about the OS and related drivers/software. Obviously given the nature of the OS I feel safe in making some basic assumption, like interrupt won’t be disable for >1ms (on Pentium class machine). This is just an assumption, there is no guaranty. Some level of confidence need to be established first, which can be increase by testing and/or experience. Other assumption I learn to trust; interrupts under QNX4 where of very short duration (for drivers I have used so far). I also learn that interrupt have priorities above those of program. I tend to see interrupt priority as a continuation of process/thread priorities.

With QNX6 InterruptAttachEvent is very interesting because it removes the need to make an assumption about the length of the ISR. It however blurs the concept of IRQ priority (I’m not even talking about shared interrupt). Since IRQ work is handle by thread, it’s quite possible a thread of lower priority is set to handle a IRQ of high priority while a thread of higher priority is set handle a lower IRQ priority. With proper design this can be avoided (or intentionally crafted) but in case of third party driver (which includes OS drivers) the task is delicate since information is not always (mostly never) available (ex: at what priority network driver IRQ are set). If thread priority don’t match IRQ priority things can get messy: Imagine thread 1 handling IRQ level 1 (lowest), pulse event was set to priority 64, meanwhile IRQ level 10 comes it, kernel sends the event of priority 50 to the thread 2. Because thread 1 is higher priority then thread 2, IRQ level 10 is not processed until thread 1 is completed. While thread 1 is working, and IRQ level 9 comes in, PIC doesn’t’ send info to OS because it lower then 9. If thread 1 takes too long to process data it’s quite possible data is lost even though IRQ level 9 is higher then level 1 and what ever the priority of the event that is handling IRQ 9. It seems to me InterruptAttachEvent introduce a greater level of uncertainty. In order to get a good idea of how a particular set of driver behave (being custom/third-party/QSS) at lot more work is required. I even wonder if it’s possible given the lack of information.

To me it comes down to being able to trust software to perform within my expectation. If I know a software makes use of InterruptAttach, I have to be concern with ISR length and IRQ priority (assuming all ISR clear source of interrupt). If a system uses InterruptAttachEvent the factors involved are IMHO more complexe.

Maybe I just need to get more experience with QNX6, but for now InterruptAttachEvent give me the impression I have lost some level of control.

IMO InterruptAttachEvent gives you more control (at least on a PC); because now you have 64 priorities to which you can assign an interrupt handler. Of course, you are still limited to the number of distinct IRQ lines provided by PC’s (which are very limited).

If your application is restricted to only dealing with interrupts, then you don’t need QNX at all, just program directly to the metal; but if you have other non-real-time applications that you want to co-host with a real-time app, then that is what a RTOS is for.

I always like to say that the purpose of a RTOS is to allow you to run non-real-time applications. Designing a pure real-time app programmed directly to the metal is “easy”. Designing a non real-time app to run on a general purpose OS is “easy”. Designing a system that is a mixture of these two types of applications is “hard” and that’s where a RTOS comes in…

I don’t see it that way since you are still limited by the number of IRQ anyway, but you do get the ability to handler ISR at lower/mixed priority then some thread.

You do have controle it’s every program is yours but otherwise you don’t. I haven’t seen documented anywhere the priority of QSS drivers (or third party) nor a way to specify the priority of the thread handling the interrupt.

With InterruptAttach I have no control over the duration of the ISR but I have controle over all of their priorities.

I’m not I fully understand the implication of your about RTOS/real-time/metal -) I’ll let my brain work on it for a while :wink:

I didn’t say that InterruptAttachEvent magically provides 64 interrupt priorities, only that you can assign an IRQ (a unschedulable event) to any of the 64 priorities that the scheduler provides. With interrupt handler only, you can only select from a range of priorities controlled by the hardware, and you can never select a priority for an IRQ that is lower than a thread (which is something I definately want to be able to do).

You two are talking at odds. And one of you understood this already.

mario is saying: When sharing an IRQ using InterruptAttachEvent() there can be no assumtion on the masking duration of the other drivers you are sharing with.

rgallen is saying: Forget sharing, when using InterruptAttachEvent() in your driver you get to efficiently perform complex I/O processing in the safety of your own process.

Yeah sorry]rgallen, I didn’t take the time to read your post properly ;-) Indeed being able to process ISR at lower then priority has its advantage, i’m not disputing that. As a matter of fact you don’t need InterrutAttachEvent to do that, and you could do it in QNX4 if you wanted to.

What troubles me it the usage of InterruptAttachEvent in program I don’t have control over, possible as evanh said masking interrupt for unknown perid of time for share interrupt and also breaking the rules of IRQ priority (that one gives me shivers).

The priority issue is not as bad as you think. The “Event” effectively decouples the handler from the IRQ. These type of drivers are expecting delays. All they want to know is: Has there been an interrupt?.

However, the convenience this provides largely sacrifices sharing because the kernel has no knowledge of how to clear the interrupt source and therefore has no option but to leave the IRQ masked.

I say largely because multiple similar devices should have no problem sharing due to them having similar expectations on processing/response times. In a loaded situation they would probably cycle in a round-robin fashion which, I believe, is desirable.

An efficient way to handle sharing in an InterruptAttachEvent() like setup would be to add a callback for the kernel to call on an IRQ. This would be an optional callback. I imagine this idea is frowned on because it breaks open the kernel to foreign code.

The callback would check it’s hardware and if it has an interrupt pending then, if the driver is waiting, send an event to the driver then clear the interrupt source and return.

Why don’t just attach the “callback” with InterruptAttach() ?

That’s not as efficient because of the required context switch to map the ISR to it’s owner thread space.

Where as when the IRQ is handled completely in the kernel there is no context switch at all, unless the scheduler decides to change to another thread.

These ideas are, of course, academic due to the required modification of a lot of drivers.

Hmm, looks a lot like both the callback method and the ISR (that merely performs the handshaking) are the intermediate handler method that bjchip was talking about. :astonished:

A callback would required some sort of mapping, since the callback would have to be called with the proper context (data segment). Otherwise you wouldn’t be able to access any global variable which make it almost useless. How would the callback know at what address the hardware sit for example.

The same way it gets to know the state of the driver. That’s just some setup details. I’d imagine the driver feeds the info into it via some special kernel functions just for that purpose.