Xilkernel: Problem with mutex

Hello,

i have created a fairly simple Microblaze-based system, just one core, opb-UART, BRAM, opb-timer and opb-intc. I wrote a small program using the xilkernel-OS which creates two threads printing a thread-specific number and the current clock_ticks. The code is given below. I expect the program to print each second a message of one thread, but that doesn't work.

When executing the program both threads seem to enter the code fragment locked by the mutex nearly at the same time as can be seen by the printed clock_ticks. The mutex is declared static and initialized in the static thread created by xilkernel_main and before creating the "Hello world"-threads.

void thread_func(int number) { while (1) { pthread_mutex_lock(&print_mutex); sleep(500); xil_printf("Ticks = %d. Thread %d says: Hello world!\r\n", xget_clock_ticks(), number); sleep(500); pthread_mutex_unlock(&print_mutex); } }

Output via UART: Ticks = 362. Thread 1 says: Hello world! Ticks = 365. Thread 2 says: Hello world! Ticks = 464. Thread 1 says: Hello world! Ticks = 468. Thread 2 says: Hello world!

Regards,

Andreas

Reply to
Andreas Hofmann
Loading thread data ...

Andreas Hofmann schrieb:

hm, I think it each thread should print 1 message once a second and that is what you see as well, so everything is working?

Antti

Reply to
Antti

Antti schrieb:

No. As the sleeping is done while the mutex is locked each thread should print its message every two seconds. As one tick is approximately 10 ms the message of thread 2 is printed 30 ms after the message of thread 1. So there must be something wrong.

Regards, Andreas

Reply to
Andreas Hofmann

Andreas Hofmann schrieb:

ok, if you say so :)

for me it wasnt so obvious that obtaining mutex lock on 'print_mutex' will disable all threads from executing!

the 30 milliseconds seems to me also correct as this the time it takes to send your hello ... over 9600 baud UART

Antti

Reply to
Antti

Antti schrieb:

The other threads should be blocked because sleep() is called while the mutex is held by the sleeping thread.

Admittedly my code immediately tries to lock the mutex after releasing it so the other threads may have no chance to execute their lock request. This seems to cause the problems because after enabling yield()-support and calling yield() after pthread_mutex_unlock() solves the problem. The program does now behave as expected.

However, i do not fully understand what the kernel is doing when yield() is missing. Shouldn't the other threads, which do not hold the lock, starve while one of the thread locks the mutex over and over again?

On the other hand, the Xilinx manual clearly states that when pthread_mutex_unlock() is called "the thread that is at the head of the mutex wait queue is unblocked and allowed to lock the mutex.". Thus calling or omiting yield() shouldn't make any difference.

Regards, Andreas

Reply to
Andreas Hofmann

Andreas,

Something is wrong. As your code is written there is no way the 2 threads can print out timestamps so close together. It's as if your pthread locking is having no affect at all.

Did you init the mutex? Is the mutex residing on some cacheable memory, and the cache hasn't been flushed? Check the details of the mutex itself, there may be limitations. On blackfin dsp mutex locking was based on their test and set instruction, which was flawed -- you had to use external memory otherwise it didn't work. There may be something similiar going on here.

-Dave

--
David Ashley                http://www.xdr.com/dash
Embedded linux, device drivers, system architecture
Reply to
David Ashley

Unblocking a thread is not the same as giving it processor time. Assuming there are only two threads, then the unblocked thread will not actually execute unless it has a higher priority than the current thread, or the current thread blocks. If the both threads have equal priority, then the blocked thread will also run if the current thread calls sched_yield(). And if the priorities are equal and the current thread uses the SCHED_RR policy, then the blocked thread will also run when the current thread's time quantum expires. If either thread uses the SCHED_OTHER policy then all bets are off. Likewise, if Xilinx's implementation is not POSIX conforming, then who knows what will happen.

Reply to
ryanrsrsrs

On a POSIX-conforming system (ie. compiler + OS + hardware as a whole), the pthread API is sufficient to achieve synchronization. No low level trick are necessary. That's the whole point.

Reply to
ryanrsrsrs

Well something's broken. The code ought to behave differently...At this point there are no options but grasping at straws...

The init code wasn't included, you can't just declare a mutex, you need to initialize it:

static pthread_mutex_t amutex=PTHREAD_MUTEX_INITIALIZER;

For example...

-Dave

--
David Ashley                http://www.xdr.com/dash
Embedded linux, device drivers, system architecture
Reply to
David Ashley

Check the behavior of sleep(). I take it sleep(500) is not meant to sleep for 500 seconds. POSIX sleep() has wierd interactions with setitimer(), ualarm(), usleep(), and SIGALRM. It can also return early due to signal delivery. Nanosleep() is easier to use.

Try the following: lock print "begin thread %i" sleep print "end thread %i" unlock

Reply to
ryanrsrsrs

To cut a long story short, Xilinx is the one to blame. Their pthread_mutex_lock implementation in xilkernel_v3 is somewhat broken.

If a mutex is locked by thread 1 when pthread_mutex_lock() is called by thread 2, thread 2 is suspended and added to the wait queue of the mutex. On release of the mutex the first thread in the wait queue is unblocked. Depending on the time slice thread 1 may run on and aquire the mutex since it is free. This happens in my case due to the tight loop.

Now comes thread 2 into action. It's unblocked and thus set to run when the time slice of thread 1 ends. Thread 2 is blocked inside pthread_mutex_lock_basic(), defined in "EDK\sw\lib\bsp\xilkernel_v3_00_a\src\src\ipc\mutex.c", by a call to process_block(). When process_block() returns thread 2 aquires the mutex _without_ checking if it is really free, which is not true in my case since thread 1 has locked it immediately after freeing it.

Best regards Andreas

Reply to
Andreas Hofmann

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.