Suppose I have two tasks, 'A' and 'B', of differing priority executing on SMP-supported VxWorks. Both 'A' and 'B' issue a command to an I/O device (such as a disk or NIC) and both block waiting for results. That is, both 'A' and 'B' are blocked at the same time. Some time later, the I/O device raises an interrupt and the ISR is invoked. The ISR then dispatches deferred work (aka "bottom-half") to a worker-task. Question: What is the priority of the worker-task?
VxWorks Device Driver Developer's Guide is a bit vague. It appears that the priority of the worker-task is set up a-priori. There are no automatic inheritance mechanisms that will increase the priority of the worker-task based upon the priorities of tasks ('A' and 'B') that are blocked waiting for results. This is similar to how threaded interrupt priorities work in PREEMPT_RT Linux. However, both QNX Neutrino and LynxOS will schedule the worker-task with the maximum priority of the blocked tasks-- Ex. priority(worker) = max_priority(A, B).
Can anyone clarify?
It depends exactly on which mechanism the "ISR dispatched deferred work" uses.
If a semaphore/messageQueue/Event is used, then the recipient task (A or B) will run at the priority specified when the task was created. In this scenario, the interrupt is essentially finished, and the task (A and/or B) are ready to run.
Whichever task is has the highest priority will get to run and perform it's work. Note that the task doesn't have access to any information from the interrupt context. If you use global structures (yuk) or pass data via a message queue, then the task could access those elements.
The network stack task (tNetTask) uses this approach, and a semaphore signals tNetTask when a packet has been received. When tNetTask has processed the packet (packet reassembly, etc...), it is then forwarded to whichever task is waiting on the corresponding socket.
It is possible to defer work from an ISR to tExcTask (via a call to excJobAdd). Note that with this approach, excJobAdd takes the pointer to a function and executes the function in the context of the tExcTask (which is at the highest priority in the system). It does not act as a self-contained task.
Note that some things like file systems, SCSI drivers, USB, etc... are much more than a simple driver with interrupts. They include a number of different components that unfortunately also increases complexity.
Related
Suppose I have a semaphore to control access to a dispatch_queue_t.
I wait for the semaphore (dispatch_semaphore_wait) before scheduling a block on the dispatch queue.
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER)
dispatch_async(queue){ //do work ; dispatch_semaphore_signal(semaphore); }
Suppose I have work waiting in several separate locations. Some "work" have higher priority than the other "work".
Is there a way to control which of the "work" will be scheduled next?
Additional information: using a serial queue without a semaphore is not an option for me because the "work" consist of its own queue with several blocks. All of the work queue has to run, or none of it. No work queues can run simultaneously. I have all of this working fine, except for the priority control.
Edit: (in response to Jeremy, moved from comments)
Ok, suppose you have a device/file/whatever like a printer. A print job consists of multiple function calls/blocks (print header, then print figure, then print text,...) grouped together in a transaction. Put these blocks on a serial queue. One queue per transaction.
However you can have multiple print jobs/transactions. Blocks from different print jobs/transactions can not be mixed. So how do you ensure that a transaction queue runs all of its jobs and that a transaction queue is not started before another queue has finished? (I am not printing, just using this as an example).
Semaphores are used to regulate the use of finite resources.
https://www.mikeash.com/pyblog/friday-qa-2009-09-25-gcd-practicum.html
Concurrency Programming Guide
The next step I am trying to figure out is how to run one transaction before another.
You are misusing the API here. You should not be using semaphores to control what gets scheduled to dispatch queues.
If you want to serialize execution of blocks on the queue, then use a serial queue rather than a concurrent queue.
If different blocks that you are enqueuing have different priority, then you should express that different priority using the QOS mechanisms added in OS X 10.10 and iOS 8.0. If you need to run on older systems, then you can use the different priority global concurrent queues for appropriate work. Beyond that, there isn't much control on older systems.
Furthermore, semaphores inherently work against priority inheritance since there is no way for the system to determine who will signal the semaphore and thus you can easily end up in a situation where a higher priority thread will be blocked for a long time waiting for a lower priority thread to signal the semaphore. This is called priority inversion.
Early Cisco routers running IOS operating system enhanced their packet processing speed by doing packet switching within the interrupt handler instead in "regular" operating system process. Doing packet processing in interrupt handler ensured that context switching within operating system does not affect the packet processing. As I understand, interrupt handler is a piece of software in operating system meant for handling the interrupts. How to understand the concept of packet switching done within the interrupt handler?
use of interrupts is preferred when an event requires some immediate attention by the operating system, or a program which installed an interrupt service routine. This as opposed to polling, where software checks periodically whether a condition exists, which indicates that the event has occurred.
interrupt service routines aren't commonly meant to do a lot of work themselves. They are rather written to reach their end as quickly as possible, so that normal execution can resume. "normal execution" meaning, the location and state previous processing was interrupted when the interrupt occurred. reason is that it must be avoided that the same interrupt occurs again while its handler is still executed, or it may be ignored, or lead to incorrect results, or even worse, to software failure (crashes). So what an interrupt service routine usually does is, reading any data associated with that event and storing it in a queue, signalling that the queue experienced mutation, and setting things such that another interrupt may occur, then resume by restoring pre-interrupt context. the queued data, associated with that interrupt, can now be processed asynchronously, without risking that interrupts pile up.
The following is the procedure for executing interrupt-level switching:
Look up the memory structure to determine the next-hop address and outgoing interface.
Do an Open Systems Interconnection (OSI) Layer 2 rewrite, also called MAC rewrite, which means changing the encapsulation of the packet to comply with the outgoing interface.
Put the packet into the tx ring or output queue of the outgoing interface.
Update the appropriate memory structures (reset timers in caches, update counters, and so forth).
The interrupt which is raised when a packet is received from the network interface is called the "RX interrupt". This interrupt is dismissed only when all the above steps are executed. If any of the first three steps above cannot be performed, the packet is sent to the next switching layer. If the next switching layer is process switching, the packet is put into the input queue of the incoming interface for process switching and the interrupt is dismissed. Since interrupts cannot be interrupted by interrupts of the same level and all interfaces raise interrupts of the same level, no other packet can be handled until the current RX interrupt is dismissed.
Different interrupt switching paths can be organized in a hierarchy, from the one providing the fastest lookup to the one providing the slowest lookup. The last resort used for handling packets is always process switching. Not all interfaces and packet types are supported in every interrupt switching path. Generally, only those that require examination and changes limited to the packet header can be interrupt-switched. If the packet payload needs to be examined before forwarding, interrupt switching is not possible. More specific constraints may exist for some interrupt switching paths. Also, if the Layer 2 connection over the outgoing interface must be reliable (that is, it includes support for retransmission), the packet cannot be handled at interrupt level.
The following are examples of packets that cannot be interrupt-switched:
Traffic directed to the router (routing protocol traffic, Simple Network Management Protocol (SNMP), Telnet, Trivial File Transfer Protocol (TFTP), ping, and so on). Management traffic can be sourced and directed to the router. They have specific task-related processes.
OSI Layer 2 connection-oriented encapsulations (for example, X.25). Some tasks are too complex to be coded in the interrupt-switching path because there are too many instructions to run, or timers and windows are required. Some examples are features such as encryption, Local Area Transport (LAT) translation, and Data-Link Switching Plus (DLSW+).
More here: http://www.cisco.com/c/en/us/support/docs/ios-nx-os-software/ios-software-releases-121-mainline/12809-tuning.html
Is there a way to basically call system(), but with a predefined niceness value (20) and low IO priority from Objective-C?
(The low IO priority setting I'm talking about is the one launchd has)
I'm trying to launch /usr/bin/purge from within my Objective-C program.
It would also be ideal for the method to be approved for the Mac App Store.
Edit: Fork and exec no more, since OSX can't really fork right. Single thread magic:
setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE);
system("nice -n 20 /usr/bin/purge");
setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_DEFAULT);
This can go anywhere, in a dispatch block if you want, or anywhere in your application. No fork in sight. Also, feel free to replace system with NSTask if you want to stay ObjCish.
How about a good old forknexec:
#include <unistd.h>
#include <sys/resource.h>
And:
if(fork()) {
/* Set IO priority */
setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE);
/*IO priority is inherited*/
execl("nice", "-n", "20", "/usr/bin/purge");
}
Let's walk through this:
fork: Nothing to see here
setiopolicy_np: This is the place where we set IO priority (like launchd). Here are the arguments:
IOPOL_TYPE_DISK: We want to limit Disk I/O. There is no other option available anyway.
IOPOL_SCOPE_PROCESS: Affects this whole process
IOPOL_THROTTLE: This is the policy itself. Accouring to the Apple documentation, it specifies this:
I/Os with THROTTLE policy are called THROTTLE I/Os. If a THROTTLE I/O
request occurs
within a small time window (usually a fraction of a second) of another NORMAL I/O
request, the thread that issues the THROTTLE I/O is forced to sleep for a certain
interval. This slows down the thread that issues the THROTTLE I/O so that NORMAL I/Os
can utilize most of the disk I/O bandwidth. Furthermore, a NORMAL I/O request may
bypass a previously issued THROTTLE I/O request in kernel or driver queues and be sent
to the device first. In some circumstances, very large THROTTLE I/O requests will be
broken into smaller requests which are then issued serially.
I/O priority is inherited, and the nice part of the command sets the nice value.
A simple way to accomplish this would be using the taskpolicy(8) tool with the -b option:
system("/usr/sbin/taskpolicy -b /usr/bin/purge");
With the -b option taskpolicy uses setpriority(2) to set the background priority(PRIO_DARWIN_BG)
Setting a process to PRIO_DARWIN_BG has this effect on itself and all its children:
"When a thread
or process is in a background state the scheduling priority is set to the lowest value, disk IO is
throttled (with behavior similar to using setiopolicy_np(3) to set a throttleable policy), and network
IO is throttled for any sockets opened after going into background state. Any previously opened sockets ets are not affected."
I have a question regarding previous question asked in VxWorks forum.
My goal is when the high priority function generates a signal the low priority function will handle it immidiately(the high priority function must be preempted)
The code is:
sig_hdr () { ... }
task_low_priority() {
...
// Install signal handler for SIGUSR1
signal(SIGUSR1, sig_hdr);
...
}
task_high_priority() {
...
kill(pid, SIGUSR1); //pid is the ID of task_low_priority
...
}
After the line:
signal(SIGUSR1, sig_hdr);
i added
taskDelay(0).
I wanted to block the high priority task so the low priority task can gain the CPU in order to execute the signal handler but it does not happen unless i do taskDelay(1).
Can any one explain why it does not work with taskDelay(0)?
Indeed, taskDelay(0) will not let lower priority tasks run because of the following:
high priority task is executing
high priority task issues taskDelay(0)
Scheduler is invoked and it scans for the next task to run, it will select the highest priority task that is "ready"
The task that issued the taskDelay(0) is ready because the delay has expired (i.e. 0 ticks have elapsed)
So the high priority task is rescheduled immediately, in this case taskDelay(0) is effectively a waste of CPU cycles.
Now in the case where you issue taskDelay(1) the same steps are followed, but the difference is that the high priority task isn't in the ready state because one tick has not elapsed, so a lower priority task that is ready can have 1 tick of CPU time then it will be preempted by the high priority task.
Now there are some poorly designed systems out there that do things like:
taskLock();
...
taskDelay(0);
...
taskUnlock();
With the intention of having a low priority task hog the CPU until some point where it then allows a high priority task to take over by issuing a taskDelay(0). However if you play games like this then you should reconsider your design.
Also in your case I would consider a more robust system, rather than doing a taskDelay() to allow a low priority task to process an event, you should send a message to a low priority task and have that low priority task to process the message queue. While your high priority task blocks on a semaphore that is given by your event handler or some thing similar. In this situation you are hoping to force a ping pong between two different tasks to get a job done, but if you add a queue that will act as a buffer, so as long as your system is schedulable (i.e. there is enough time to respond to all events, queue them up and fully process them) then it will work.
Update
I assume your system is supposed to be something like this:
Event occurs (interrupt driven?).
High priority task runs to gather data.
Data is processed by low priority task.
If this is the case the pattern you want to follow is actually quite simple, and in fact could be accomplished with just 1 task:
Interrupt handler gathers data, and sends a message (msgQSend()) to task.
Task is pending on the message queue with msgQReceive.
But it might help if I knew more about your system (what are you really trying to do) and also why you are using posix calls rather than native vxworks calls.
If you are new to real time systems, you should learn about Rate monotonic analysis, there is a very brief summary on wikipedia:
http://en.wikipedia.org/wiki/Rate-monotonic_scheduling
Also note that in VxWorks a "high priority" is 0, and "low priority" is 255, the actual numbers are inversely related to their meaning :D
this is exactly the point i dont understand how the low priority task will get some CPU time when the high priority task is running?
High priority task will continue run till it gets blocked. OInce it gets blocked, lower priority task that are ready run will run.
My answer has 2 parts:
1. How to use correctly task Delay with vxWorks
2. TaskDelay is not the correct solution for your problem
First part:
TaskDelay in vxWorks can confused:
taskDelay(0) – don't perform delay at all!!!
It is a command to the scheduler to remove the current task from the CPU. If this is still the highest priority task in the system, it will return to the head of the queue with no delay at all. You will use this command if the scheduler configured to FIFO in case tasks in the same priority and your task have a CPU real time consumer function to run, the can try to release the CPU for other tasks in the same priority (nice).
BTW, it is the same as taskDelay(NO_WAIT).
TaskDelay(1) – this will delay the calling task sometime between zero (!!!) to 1 system tick. The delay in vxWorks finish at a round system tick.
TaskDelay(2) – sometime between 1 system tick to 2 system ticks.
3 …… (understood…)
TaksDelay(-1) (A.K.A taskDelay(WAIT_FOREVER)) – will delay the task forever (not recommended).
Second part:
Using taskDelay to enable low priority task might be a wrong idea. You didn't provided the all problem information but please note that delaying the high priority task will not ensure your low priority task will run (regardless the sleep time you'll write). Other tasks in highest priority from your high & low priority tasks might run for the all 'sleep time'.
There are several synchronized methods in vxWorks, like binary semaphores, changing task priority, signals, …
1) How can the processor recognize the device requesting the interrupt?
2) Given that different devices are likely to require different ISR, how can the processor obtain the starting address in each case?
3) Should a device be allowed to interrupt the processor while another interrupt is being serviced?
4) How should two or more simultaneous interrupt requests be handled?
1) How can the processor recognize the device requesting the interrupt?
The CPU has several interrupt lines, and if you need more devices than there are lines there's an "interrupt controller" chip (sometimes called a PIC) which will multiplex several devices and which the CPU can interrogate.
2) Given the different devices are likely to require different ISR How can the pressor obtain the starting address in each case?
That's difficult. It may be by convention (same type of device always on the same line); or it may be configured, e.g. in the BIOS setup.
3) Should a device be allowed to interrupt the processor while amother interrupt is being services?
When there's an interrupt, further interrupts are disabled. However the interrupt service routine (i.e. the device-specific code which the CPU is executing) may, if it's willing, reenable interrupts if it's willing to be interrupted.
4) How should two or more simultanement interrupt requests be handled?
Each interrupt has a priority: the higher-priority interrupt is handled first.
The concept of defining the priority among devices so as to know which one is to be serviced first in case of simultaneous requests is called priority interrupt system. This could be done with either software or hardware methods.
SOFTWARE METHOD – POLLING
In this method, all interrupts are serviced by branching to the same service program. This program then checks with each device if it is the one generating the interrupt. The order of checking is determined by the priority that has to be set. The device having the highest priority is checked first and then devices are checked in descending order of priority.
HARDWARE METHOD – DAISY CHAINING
The daisy-chaining method involves connecting all the devices that can request an interrupt in a serial manner. This configuration is governed by the priority of the devices. The device with the highest priority is placed first.