SemaphoresA: 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?
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).
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!
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.
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...
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)
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).