There is one new predefined local process variable:
_prioritywhich holds the current priority of the executing process. The default priority is 1.
There are two new predefined functions:
get_priority(p) which returns the priority of process p set_priority(p,c) which sets priority of process p to cIn the above function calls, the parameters p and c can be any valid Promela expression.
When process priorities are used then only the highest priority enabled process can run. Process priorities must be in the range 1..255.
/*** Example 1 ***/ /* the use of 'priority' tags enforces priority based scheduling it can also be combined with provided clauses to finetune the scheduling choices */ byte cnt; active proctype medium() priority 5 { set_priority(0, 8); printf("medium %d - pid %d pr %d pr1 %d\n", _priority, _pid, get_priority(_pid), get_priority(0)); cnt++ } active proctype high() priority 10 { _priority = 9; printf("high %d\n", _priority); cnt++ } active proctype low() priority 1 { /* * this process can only execute if/when it is the * highest priority process with executable statements */ assert(_priority == 1 && cnt == 2); printf("low %d\n", _priority); }
/*** Example 2 - semaphore routines with priority inversion ***/ bool sem_busy; byte sem_owner; /* pid of semaphore owner */ byte sem_prior; /* original priority of owner */ inline sem_take() { atomic { do :: !sem_busy -> sem_busy = true; sem_owner = _pid; sem_prior = _priority; break :: else -> if :: get_priority(sem_owner) < _priority -> set_priority(sem_owner, _priority); (!sem_busy) :: else fi od } } inline sem_give() { atomic { sem_busy = false; sem_owner = 0; _priority = sem_prior /* we could get blocked after this */ } }
/*** Example 3 ***/ chan q = [1] of { bool }; bool ok = false; active proctype high () priority 10 { bool x; q?x; /* highest priotity, but blocked */ ok = true } active proctype low () priority 5 { atomic { q!true; /* executes first */ assert (ok) /* assertion fails */ } }
/*** Example 4 ***/ /* * a high priority process consumes data * produced by a low priority process. * data consumption and production happen under * the protection of a mutex lock * the mutex lock conflicts with the scheduling priorities * which can prevent the high priority process from running * if a medium priority process is also present */ mtype = { free, busy, idle, waiting, running }; show mtype h_state = idle; show mtype m_state = idle; show mtype l_state = idle; show mtype mutex = free; proctype high() { end: do :: h_state = waiting; atomic { mutex == free -> mutex = busy }; h_state = running; /* critical section - consume data */ atomic { h_state = idle; mutex = free } od } proctype medium() { end: do :: m_state = waiting; m_state = running; m_state = idle od } active proctype low() /* default low priority 1 */ { end: do :: l_state = waiting; atomic { mutex == free -> mutex = busy}; l_state = running; run high() priority 10; /* starved by medium() */ run medium() priority 5; /* prevents low() from releasing lock */ /* critical section - produce data */ atomic { l_state = idle; mutex = free }; assert(false) /* not reachable, because proctype medium runs */ od }
Return to Spin homepage | Page last updated May 4, 2012 |