Data Structures | Enumerations | Functions

# Process management functions
[Pre-emptive, soft real-time scheduler]

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.

## Detailed Description

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.

- If a process is in normal level, then it can be preempted (kicked off from the CPU) by interrupt routines, the kernel itself or by any process that has higher priority and becomes active.

- If a process is at the cooperative level, the interrupts and the kernel itself can interrupt it, but even if a higher priority process becomes ready, it will not be allowed to run until the process at the cooperative protection level voluntarily gives up the CPU, either by dropping is protection level to normal or by calling a kernel function that suspends it.

- If a process is in disabled IRQ mode, then the processor's IRQ (hardware interrupt will be disabled). The only thing that can possibly cause the CPU to execute code other than that of the protected process if the fast interrupt, FIQ. Note, however, that in that level it is illegal for the process to call any kernel function that can cause it get suspended.

- If a process is in disabled FIQ mode, then both IRQ and FIQ are disabled on the CPU. The process has absolute control over the processor and will not be interrupted for any reason. Like in the disabled IRQ case, it is illegale for the process to call any function that could potentially suspend it.

## Enumeration Type Documentation

enum BX_PROT

Process protection levels.

Enumerator:

  BX_PROT_NORM | Normal, not protected, preemptable mode.
  BX_PROT_COOP | Cooperative mode, suspend only when requested.
  BX_PROT_IRQD | IRQ disabled mode, no preemption or suspension.
  BX_PROT_FIQD | IRQ and FIQ disabled, no preemption or suspension.

## Function Documentation

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.

Parameters:

  | prio | The requested new priority. If this value is negative, then no priority change is performed but the current real priority is returned.

Return values:

  | BX_ERR_CONTEXT | The function was not called from an user context
  | >=0 | The previous real priority of the caller

Attention:
  This function should not be called from an ISR or delayed ISR. This function does not suspend the caller but can cause a context switch as a result of the priority change.

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.

Parameters:

  | prot | The required new protection level

Returns:
  The protection level before the call

Attention:
  This function does not suspend the caller but can cause a context switch as a result of the priority change.

Note:
  If called from a soft ISR with a parameter of BX_PROT_COOP, it may not actually enable the IRQ level interrupt if the kernel's event queue is over the watermark. Therefore, in a soft IRQ handler, even if you know that an IRQ is pending, you should not expect it to be accepted immediately after this call.

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.

Parameters:

  | prot | The desired protection level

Returns:
  The protection level before the call

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.

Returns:
  The process descriptor of the caller or NULL if the call is from an interrupt context.

int BX_ProcSpawn | ( | BX_PROC * | proc,
|  | BX_PROC_FUNC | func,
|  | void * | parm,
|  | int * | stack,
|  | unsigned int | prio,
|  | BX_PROT | prot |
| ) |  |  |

Creates a new process.

Parameters:

  | 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.

Return values:

  | >0 | Success
  | BX_ERR_CONTEXT | The function was called from an ISR context.

Attention:
  This function should not be called from an ISR or delayed ISR. This function does not suspend the caller but can cause a context switch if a higher priority process is created by the call.