This group of functions is responsible for the handling of processes. More...
Data Structures | |
| struct | BX_PROC |
| Process descriptor object. More... | |
Enumerations | |
| enum | BX_PROT { BX_PROT_NORM = 0, BX_PROT_COOP = 1, BX_PROT_IRQD = 2, BX_PROT_FIQD = 3 } |
Process protection levels. More... | |
Functions | |
| int | BX_ProcNice (int prio) |
| Change the priority of the caller. | |
| int | BX_ProcProtLower (BX_PROT prot) |
| Lowers the protection level of the caller. | |
| int | BX_ProcProtRaise (BX_PROT prot) |
| Raises the caller's protection level. | |
| BX_PROC * | BX_ProcSelf (void) |
| Returns the caller's process descriptor. | |
| int | BX_ProcSpawn (BX_PROC *proc, BX_PROC_FUNC func, void *parm, int *stack, unsigned int prio, BX_PROT prot) |
| Creates a new process. | |
This group of functions is responsible for the handling of processes.
Processes have two attributes. One is their priority. It is simply a number, assigned by you. The kernel selects the process with the highest priority to run. There is no timeslicing between identical priority processes, if a process starts to run, it is let to run until it goes to wait or a higher priority process becomes active.
A process actually has two priorities assigned to it. One is the number that you set as its priority. It is called its real priority. However, it is possible that the kernel temporarily raises the priority of a process through the priority ceiling or priority inheritance mechanism. That elevated priority is called the effective priority. When the kernel selects the process to run, it looks at the effective priority of the processes.
The other attribute is the process' protection level. It indicates what can interrupt the process. Four levels are defined.
| enum BX_PROT |
| int BX_ProcNice | ( | int | prio | ) |
Change the priority of the caller.
The real priority of the caller will be set to the given value. If the priority is higher than the current effective priority of the caller, then the effective priority will be elevated to the new level. If the new priority is lower than the effective priority of the caller, then the effective priority will be adjusted, subject to priority ceiling and priority inheritance rules. If the requested priority is higher than BX_MAX_PRIO, then it will be limited to that value.
| prio | The requested new priority. If this value is negative, then no priority change is performed but the current real priority is returned. |
| BX_ERR_CONTEXT | The function was not called from an user context | |
| >=0 | The previous real priority of the caller |
| int BX_ProcProtLower | ( | BX_PROT | prot | ) |
Lowers the protection level of the caller.
The function lowers the protection level of the caller if the caller was at a level higher than the parameter. If the caller's protection level is already at or below the parameter, the function does not change the caller's protection level. If the function is called from an ISR, then the protection level can not be lowered below BX_PROT_IRQD, if called from a soft ISR then the level can not be lowered below BX_PROT_COOP, or, if the kernel disabled interrupts due to the event queue being over the watermak, below BX_PROT_IRQD. If the requested level is out of the allowed boundaries, then it will be changed to be between the boundaries.
| prot | The required new protection level |
| int BX_ProcProtRaise | ( | BX_PROT | prot | ) |
Raises the caller's protection level.
The parameter is one of the defined protection levels. If the current protection level is is lower than the one specified by the parameter, then the caller's protection level will be elevated to the desired level. If the requested level is less than or equal to the current protection level, then the function does nothing. In any case, the function returns the protection level before the call. This function can be called from interrupt service routines as well as soft interrupts. A real ISR is always at least at level BX_PROT_IRQD, a soft interrupt is at least at level BX_PROT_COOP (even though soft interrupts can not call kernel functions that would suspend them). The function's intended usage, when called from ISR-s or soft interrupts is to protect a short bit of code from FIQs or IRQs. It should be noted that in an ISR, especially if you are in ARM mode, it is quite faster to disable the FIQ by a call to BX_FiqDisable() call than calling this function. This, in an ISR the two fragments below have the same semantics, although the second is more efficient:
void my_isr( void ) { int old_status; ... do something ... // now we must protect ourselves from FIQs old_status = BX_ProcProtRaise( BX_PROT_FIQD ); // Do the protected bits ... we're protected ... BX_ProcProtLower( old_status ); } void my_isr( void ) { int old_status; ... do something ... // now we must protect ourselves from FIQs old_status = BX_FiqDisable(); // Do the protected bits ... we're protected ... BX_FiqRestore( old_status ); }
However, the same is not true for functions that can be called from ISRs as well as from soft interrupts or user code. In that case the efficient approach of directly manipulating the processor's status register is not sufficient because the kernel is not notified about the status change. This then can result in lost kernel events, context switching a process while the interrupt is disabled and other very hard to debug problems. Therefore, it is advised that if you are not absolutely certain that the code fragment that needs FIQ protection will never, ever be called from a context other than a real IRQ ISR, use the BX_ProcProtRaise() and BX_ProcProtLower() mechanism. If you are sure that the fragment is only executed within an IRQ ISR, then it is more efficient to use the BX_FiqDisable() and BX_FiqRestore() functions. Note that the latter function pair does not check if the caller is an IRQ ISR or not (the check is omitted for efficincy) and thus you need to be careful with them.
| prot | The desired protection level |
| BX_PROC * BX_ProcSelf | ( | void | ) |
Returns the caller's process descriptor.
The function, if called from a user process, returns the process descriptor of the caller. If it is called from an interrupt context, either a real interrupt or a delayed interrupt, it returns NULL.
| int BX_ProcSpawn | ( | BX_PROC * | proc, | |
| BX_PROC_FUNC | func, | |||
| void * | parm, | |||
| int * | stack, | |||
| unsigned int | prio, | |||
| BX_PROT | prot | |||
| ) |
Creates a new process.
| proc | Pointer to a process descriptor that will hold the internal state of the newly created process. | |
| func | Pointer to a function returning void and receiving a void pointer. This function will be the entry point of the new process. This function must not return, if it does, the system will crash. | |
| parm | The parameter that will be passed to the function. | |
| stack | The initial stack pointer for the new process. It must be aligned on a 32-bit word boundary. If you use and unsigned int array, declared like stk[S_SIZE] then you should pass a pointer to just behind the last element of the array. That is, you should pass stk+S_SIZE. If you pass an incorrect stack pointer, the system will crash. It goes without saying that the stack areas for processes must be distinct, even if you start the same function for different processes. Do not laugh. I've seen it done. | |
| prio | The initial priority of the process, between BX_PRIO_MIN (least important) and BX_PRIO_MAX (most important). If the parameter is out of these bounds, it will be cropped. | |
| prot | The initial protection level of the process. If the level passed is higher than BX_PROT_FIQD, then it will be set to BX_PROT_FIQD. |
| >0 | Success | |
| BX_ERR_CONTEXT | The function was called from an ISR context. |
1.6.3