Re: Using/misusing k_sem_init()


Benjamin Walsh <benjamin.walsh@...>
 

Hi Piotr,

Sorry for the late response.

I'm reviewing my new code for Atmel SAM low level Ethernet driver and
there is one place where I have a troubling use of k_sem_init()
function. Very shortly my situation:

As is typically the case Atmel's Ethernet MAC module is using a so
called descriptor list to define a linked list of transmission and
reception buffers. These shared buffers are then used to pass data
between MAC module and low level Ethernet driver.

Let's focus on the transmit path. Assuming we have two transmission
buffers and each buffer can store one full Ethernet frame the Ethernet
driver can send up to two frames to the MAC module but to send a third
frame it has to wait until a free buffer becomes available. This is a
perfect case for using counting semaphores.

During driver initialization phase we would call

k_sem_init(&tx_sem, 2, 2);

to initialize semaphores and then k_sem_take() in transmit thread every
time we send a frame and k_sem_give() in IRQ handler every time the MAC
module has read all the data from the transmit buffer. So far so good.
However, now we can have a situation where the driver (transmit thread)
has sent two frames, stopped on k_sem_take() call when trying to send a
third one and at that moment an unrecoverable transmission error
happens. At this point I would like to reinitialize the descriptor list
and also reinitialize the semaphores, i.e. I would like to call
k_sem_init() while there is a thread waiting for the very semaphore to
become available.
What is the behaviour you expect exactly ? What would a semaphore
re-init signal to the thread pending on the semaphore in your
application ?

I can tell you that with the current implementation of k_sem_init(), the
thread would not be awakened, but the wait queue would be reinitialized,
so that thread would be "lost".

You could give the semaphore twice (since you initialize it with '2') to
flush the threads pending on it, but that would probably just cause them
to pend again on the semaphore. Worst, the thread would probably just
think it got the semaphore and just try to do the operation expected of
it when it is able to get the semaphore.

Would that be OK, is there a better solution?
One thing you could do would be to abort the thread, then re-init the
semaphore, then respawn the thread.

We could maybe add a k_sem_flush() API, that unpend all threads waiting
on the semaphore, but returning them an errno.

Cheers,
Ben


Thanks and regards,
Piotr
--
Benjamin Walsh, SMTS
Wind River Rocket
www.windriver.com
Zephyr kernel maintainer
www.zephyrproject.org

Join devel@lists.zephyrproject.org to automatically receive all group messages.