portENTER_CRITICAL in xSerialPutChar

daverm wrote on Sunday, September 28, 2008:


I have a couple of questions, albeit dumb ones, with the xSerialPutChar() example code.
1. Why is the use of the lTaskWaiting variable necessary? Don’t the semaphores handle that?
2. Why is it necessary to wrap everything in a critical section? Especially with the blocking xSemaphoreTake() call. How does it unblock if interrupts are disabled? 

        /* Can we write to the FIFO? */
        if( UART1->FR & serTX_FIFO_FULL )
            /* Wait for the interrupt letting us know there is space on the
            FIFO.  It is ok to block in a critical section, interrupts will be
            enabled    for other tasks once we force a switch. */
            lTaskWaiting = pdTRUE;
            /* Just to be a bit different this driver uses a semaphore to
            block the sending task when the FIFO is full.  The standard COMTest
            task assumes a queue of adequate length exists so does not use
            a block time.  For this demo the block time is therefore hard
            coded. */
            xReturn = xSemaphoreTake( xTxFIFOSemaphore, serTX_BLOCK_TIME );
            if( xReturn )
                UART1->DR = cOutChar;
            UART1->DR = cOutChar;
            xReturn = pdPASS;

rtel wrote on Sunday, September 28, 2008:

I don’t know which comtest you are referring to without doing a search for this code.  They are all different, but are only meant to demonstrate different features and not as good examples of how an efficient interrupt controller could be written.  In fact they are normally deliberately inefficient and designed to create as many interrupts as possible in order to test the port.

Generally if a critical section is used it is to prevent race conditions on one or more of the variables or UART registers.  In this case it might be to protect the lTaskWaiting variable.

In most of the ports teach task maintains its own critical nesting and interrupt status.  It is therefore possible to yield from a critical section to a task that has interrupts enabled, with the intention of ensuring that interrupts are disabled when the original task next executes.  Newer ports tend not to support this behaviour because they use a different mechanism to perform the context switch.