[Home]Semaphores

Last edit: Peter Favrholdt on December 29, 2006 23:07 (2885 days, 20 hours and 18 minutes ago) (diff)
Rtai.Dk | RecentChanges | Preferences | DIAPM RTAI

Q: How does one share semaphores between two modules?

A: my shared semaphores are declared in a "struct" : if you share the struct, you share the semaphore.

>Q: What is meant with "share the struct"? Just using the same struct in both modules?


Q: Is it possible to share a semaphore between a +LXRT task and a module?

A: Between a lxrt process and rtai module, you have examples I think, using rt_register to share the name of the object you want to share (cf README.LXRT).


Q: I'm planning to use shm shared mem instead of fifo

To develop some kind of handshake to avoid concurrent write to shared area it's natural to me to made some job like this:

create a variable in shm named usage_flag

Every task that need to access shm area do something like this:

 if usage_flag==0 then nobody is using shm area
 usage_flag=task_unique_id
 if usage_flag==task_unique_id -> ok task can use this shm
 Do task_job on shm area
 usage_flag=0

The question is:

Should I declare 'volatile' the shm usage_flag variable to be sure it is always reloaded from memory, or there is some hidden mechanism that do this job for me?

A: To answer your question - yes, the flag should be volatile.

But the sequence you listed won't always work. Assume that usage_flag is initially 0

 task 1 tests flag, finds it 0
 task 1 gets prempted, task 2 runs
 task 2 tests flag, finds it 0
 task 2 sets flag to "2"
 task 2 tests flag, still "2"
 task 2 starts using the shm
 task 2 gets prempted, task 1 runs
 task 1 sets flag to "1"
 task 1 tests flag, still "1"
 task 1 starts using the shm, even though task 2 isn't finished - BAD

The test for 0 and set to unique_id MUST be an atomic operation. If it is, then the second test is not needed, and you also don't need unique_id, it can be any value.

You can either do this with whatever atomic operations are available on your platform, or you can use a semaphore. But the original design will fail, eventually. It will only fail if task1 gets prempted between the test for zero and the set to unique_id. This is a very short time, so it may fail only rarely and be very hard to debug!


Q: What about using POSIX function (mutexes)?

A: If you refer to the native Linuxthreads support, this won't work. RT tasks and native Linux threads do not share the same scheduler.


Q: I would like to use semaphores to manage access to shared memory between linux user sw and RT kernel modules. I need NOT to block or queue tasks, I just need to check if shared mem is free from both side and the first that try to take the memory area prevent the other task to access the mem. The task that find the mem area locked just skip the access to the memory and uses old values it has.

It seems that rtai_sem_wait_if() is the right choice but it doesn't return if access is possible or not?

A: Don't count much on documentation. AFAIK, at least rt_sem_wait_timed DOES returns SEM_TIMOUT if getting the semaphore was not possible. Better have a look at the code. And you could always use rt_sem_wait_timed(sem, 0);

A2: I think the rt_sem_xxxx functions are designed for task to task communication, not task to user. I'm not sure about this, and would like to hear from someone who really knows. You might need to use the rtf fifo based semaphores instead. In that case rtf_sem_trywait() is probably the right choice.

Regarding the return value of rtai_sem_wait_if(). According to the docs, it returns "the number of events already signalled", which isn't very clear.

I think that means it returns original value of the semaphore. If that value is negative, somebody else is using the protected resource, and you need to skip it (use old data, or whatever).

If that value is zero or higher, then the resource was available, and rt_sem_wait_if() has atomically decremented it to tell other tasks that you are now using the resource. When you are done with the resource, call sem_signal to increment it again, making it available for other tasks.

Hopefully someone more knowledgeable will either confirm or correct this...

A3: I solved this problem with fifo-based semaphores. Only make a Fifo and then rtf_sem_post in Kernel-space and rtf_sem_wait in user-space. Works fine.

Further question : Where the fifo semaphoer should be created ? in user space or kernel space ? the fifo is created in kernel side ?

A4: if you only need to poll for availability and if your target processor supports it efficiently, you could also use the (atomic) compare-and-exchange instruction, no RTAI involved here. E.g. if you are running a x86 box, you might want to have a look at include/asm-i386/system.h for the definition of cmpxchg().

You could use it this way provided the "shmem" pointer is correctly mapped to the shared area, on each side (RT/user):

struct shared_area {

       int semlock; /* 0=unlocked, 1=locked */
       char data[...];

} *shmem;

if (cmpxchg(&shmem->semlock,0,1) == 0) { /* Swing succeeded */
    /* Access granted, semlock is now "1": consume new data */
    ...
    /* release the lock */
    shmem->semlock = 0; /* or xchg(&shmem->semlock,0) if safer on your arch. */
} else {
    /* Access denied: consume old data */
  }
}

Pros: Fast, simple and efficient. Works for both sides (RT/user).

Cons: Might eat bus bandwidth on SMPs if access contention is really high (e.g. one side's work cycle on the shared area is lengthy while the "other side" spins waiting for it to end on another processor).

The uniprocessor case is even simpler: since a RT task has absolute priority over a plain Linux one under RTAI, no Linux task could be found spinning on the lock until the RT side has released it before suspending itself. Conversely, a RT task failing to grab the lock would have to yield the CPU for a while, so the user task could have a chance to release this lock.

However, you might not always be able to predict how many times max both sides would have to try to grab the lock before actually being granted the access, but this might be the price to pay if you really want to avoid a queuing mechanism...


Q: Is it necessary to synchronize integer which is modified by interrupt handler function and used for reading value in rt_task?

A: Variables that are of the same size (or less) as the platform you are working on are always read and written atomically IF they are properly aligned in memory.

For example i think that a 32bit integer that is placed on an odd 16 bit boundary is not written atomically, but unless you manually modify alignment of your project variables, this is not a problems.

Basically you should only do this if your variabale was declared as the same type as you use it. It is dangerous writing integers using pointer arithmetic in a byte array, because your write action might not be properly aligned. in that case, the write action is not atomically (this might be different in linux, but it is like this in windows)


Q: What mechanism can I use to protect a data structure (struct) that will be read/written by both, realtime task (1 kHz) and linux kernel (10Hz)? (FIFOs are NOT acceptable) Is the only way to block interrupts or lock the scheduler??

A: You can use rt_spin_lock_irqsave, even within the Linux kernel. This is legal as long as the protected code fragment has a deterministic execution time (e.g. a simple variable access).


Edit text of this page | View other revisions | Download Rtai.dk
Search: