A.albin
A.albin

Reputation: 274

Give access to a resource based on thread priority/privilege

I am not a developer, I'm just playing with programming by trying to make my workplace more autonomous. I am currently trying to get a range of 9 threads with all different priorities (0: highest 8: lowest) to use the same UART port.

As I have to send emergency request I'd to create a lock that allow the highest priority thread to go first on the resource.

I also have to let the receive_data IRQ thread get the hand on the UART port as soon as it occur(or as soon as possible, hardware UART buffer is 500 bytes long).

I have been looking around and using nested mutex is going to prevent me to make the code evolve if I need more priority levels/thread (or at least will need a fair amount of coding).

I've read this question : How to give priority to privileged thread in mutex locking? and the second answer looks like what I wish for...but I cant understand how to implement the process.

As the question is a bit old, is there another way to do what I want? If not, can I get a more readable version of it (woodworker)?

Question: How to protect the access to the UART reader/writer & give priority access to thread based on their priority level?

Note:

Threads are currently reading one fifo each and are sleeping while the fifo is empty and start when something is put in their respective fifo.

Threads then process the command/data in a format that can be interpreted by the hardware and sent via UART.

I try to do that as I realized that sometimes emergency commands where waiting ~1s or more before being processed when I was using a single thread and the fifo was heavily populated.

Also, sorry if my English is giving you goose bump.

Upvotes: 0

Views: 247

Answers (1)

Ebya
Ebya

Reputation: 428

As mentioned in comments its a complicated task.

One way to do it will be to create a class like this one:

class UART_access_manager

{

typedef std::multimap<int, dispatch_semaphore_t> priority_map_t;
public:

 UART_access_manager();
~UART_access_manager();
void access_manager(unsigned int prio, dispatch_semaphore_t pSem);


private:

void amInext(unsigned int prio);
void process_priority(unsigned int prio);
void priority_locker(unsigned int prio);
void priority_unlocker(unsigned int prio);


int count;
std::mutex data_mtx, priority_0_mtx, mtx;
priority_map_t priority_map;
};

note I build the test on OSX and un-named semaphore can't be used, I didn't check if dispatch is available on other OS (probably not as its an apple lib).

UART_access_manager::UART_access_manager()

{

}
UART_access_manager::~UART_access_manager()
{

}



 /*********************************************************************
  *
  * Function:        void UART_access_manager::access_manager(unsigned

int prio, dispatch_semaphore_t pSem)
 *
 * Description:     add an UART access request to the queue based on priority & start process based on type
 *
 * Notes:           0 is highest
 *
 * Returns:         none
 *
 *********************************************************************/

void UART_access_manager::access_manager(unsigned int prio, dispatch_semaphore_t pSem)//, add parameters at will
 {
 int counter = 1; //debug only
 while (counter) //should check for termination criteria
 {
    //check if something was pushed on the file descriptor

    if( counter == 10) //add run condition
    {
        counter = 0; //debug

        priority_locker(prio);

        priority_map_t::iterator it = priority_map.insert(std::pair<int, dispatch_semaphore_t>(prio, pSem) );
        printf("\n thread with priority %d added to queue(size %lu)", prio, priority_map.size());
        amInext(prio);

        priority_unlocker(prio);

        while(dispatch_semaphore_wait(pSem, DISPATCH_TIME_NOW) != 0){};



        priority_locker(prio);
        // do the actual job
        process_priority(prio);
        // done, remove yourself
        priority_map.erase(it);
        if( ! priority_map.empty() )
        {
            // let next guy run:
            dispatch_semaphore_signal((priority_map.begin()->second));
        }
        priority_unlocker(prio);
    }
    else
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(50)); //test purpose only
        counter++;
    }

 }
}


/*********************************************************************
 *
 * Function:       void UART_access_manager::amInext(unsigned int prio)
 *
 * Description:    check if current priority has to run next or not
 *
 * Notes:           0 is highest
 *
 * Returns:        none
 *
 *********************************************************************/
 void UART_access_manager::amInext(unsigned int prio)
{

 if(priority_map.begin()->first == prio) dispatch_semaphore_signal(priority_map.begin()->second);
}


/*********************************************************************
*
* Function:        void UART_access_manager::process_priority(unsigned 
int prio)
*
* Description: TODO
*********************************************************************/
void UART_access_manager::process_priority(unsigned int prio)
{
 printf("\n    Priority_%d running \n",prio);
 //TODO
}

/*********************************************************************
*
* Function:       void UART_access_manager::priority_locker(unsigned 
int prio)
*
 * Description:     lock mutex in a way to guarantee priority event 
 to 
 *                  get the fastest lock possible
 *
 * Notes:           0 is highest
 ******************************************************************/
 void UART_access_manager::priority_locker(unsigned int prio)
 {
 //Low-priority threads: lock mtx, lock priority_0_mtx, lock data_mtx, 
  unlock priority_0_mtx,
 //High-priority thread: lock priority_0_mtx, lock data_mtx, unlock 
  priority_0_mtx,
  //this will insure that max priority level get privileged access to 
 the data

if(!prio)
 {
    priority_0_mtx.lock();
    data_mtx.lock();
    priority_0_mtx.unlock();
 }
else
 {
    mtx.lock();
    priority_0_mtx.lock();
    data_mtx.lock();
    priority_0_mtx.unlock();
 }
}

/*********************************************************************
 *
 * Function:        void 
 UART_access_manager::priority_unlocker(unsigned int prio)
 *
 * Description:     unlock mtx based on the mutex locked by the 
 priority level
 *
 * Notes:           0 is highest
 *
 * Returns:         none
 *
 *********************************************************************/
void UART_access_manager::priority_unlocker(unsigned int prio)
{
if(!prio)
 {
    data_mtx.unlock();
 }
else
 {
    mtx.unlock();
    data_mtx.unlock();
 }
}

Code is verbose to be easy to understand, and will do nothing as it, you are progressing nicely, see it as a assignment, if you have any question don't hesitate to comment, I'll reply.

(HS: what are you trying to do ?)

Things you'll learn: std::multimap std::mutex semaphores classes

Upvotes: 1

Related Questions