The most exciting thing about this world is its ever changing quality.

Showing posts with label Xenomai. Show all posts
Showing posts with label Xenomai. Show all posts

Wednesday, August 26, 2009

Real time signal driven between Kernel and User space

I have written a blog before about the standard usage of /proc and /dev interface as IPC between kernel space and user space applications. Of course you can do clever things such as asynchronous I/O (AIO) and non-blocking system calls, but they do not really solve the problem, if what we need is a real event driven rather than thread polling.

For standard non-real time Linux, popular ways include socket (relying on which, netlink is constructed), signalling, mapping memory. (These are all I know, please tell me if there are other tricks I don't!) There are other tricks like upcall (using call_usermodehelper in the kernel module to invoke user space program) but they are rather hacks and not well supported during porting to different hardware platforms. Of course via you can use named pipes or fifo (mknod and mkfifo) which are essentially system level device node based (similar to /dev interface) communications.

(To be extreme, here is what I have always believed - the only reason why we are having the difference of user space as opposed to kernel space is you can do whatever you want in user space without screwing up the whole os, which is protected and can allow others like you to screw up the system independently. After 2.6, the whole Linux kernel can be considered as a single process, with multiple concurrent, schedulable threads.)

Basically, signals can be sent from kernel and some can be queued if you choose to. The Linux signal queue is interrupt-safe. I won't go through the whole list of signals available and APIs to use as you can find them C&P all over the net. What I would like to note here is POSIX.4 Real Time Signals or known as RT signals. They are a group of signals (between SIGMIN and SIGMAX) supported by the Linux kernel which overcome some of the limitations of traditional UNIX signals. First of all, RT signals can be queued to by the kernel, instead of setting bits in a signal mask as for the traditional UNIX signals. This allows multiple signals of the same type to be delivered to a process. In addition, each signal carries a siginfo_t payload which provides the process with the context in which the signal was raised. To say process is a little confusing, in fact, you can signal to specific thread or a group. The catch here is you need to specify carefully which type of signal it is when you generate them in the kernel (unfortunately they need to be manually mapped to the send_sigxxx APIs you will be using to trigger the signal, i.e. if you want to use sigqueue, the si_code has to be SI_QUEUE. Unluckily, some Linux porting doesn't support sigqueue, e.g. Blackfin and PPC. There are workarounds. You can still use send_signal_info to generate signal with siginfo_t payload to queue the RT signal, but be aware you can't use _sifields. _rt. si_sigval. sival_ptr to pass a 32 bits pointer of a struct and hope to use it the same way as the value you can pass with sigqueue, you can only pass a 32 bits value in the union. I learnt it the hard way...)

One problem with RT signals is that the signal queue is finite, and hence, once the signal queue overflows, a server using RT signals has to have some fall backs. Good thing about RT signals is that they have a very low overhead. They also provide a very much software interrupt-driven approach, which to my mind is quite intuitive as you think about it. All the interesting events originally will come from hardware interface, pass to device drivers sitting kernel. What is more efficient than building your higher logic on these events?

Also, I have wrapped up these signal handlers in an I/O lib, where it sits in user space, elegantly creating and posting events in user spaces, to those who are interested - a post-office like publish-subscribe mechanism. This way, you wouldn't have to worry about errant signals. In the kernel, I have added a linked list to maintain all the threads (task_struct) which have initiated the requirement to be signalled. They will be signalled in a simple round-robin way. Code is dead simple:

// in the kernel driver
list_for_each(ptr, &user_tasks.list)
{
entry = list_entry(ptr, struct user_task_struct, list);
memset(&info, 0, sizeof(struct siginfo));
info.si_int = pdev->data;
info.si_signo = SIGGPIBUTTON;
info.si_errno = 0;
info.si_code = SI_QUEUE;
info.si_uid = pdev->minor_node_id; // stole this field for additional info
err = send_sig_info(SIGGPIBUTTON, &info, entry->thread);
}

// in the I/O lib
memset(&m_actBt, 0, sizeof(m_actBt));
m_actBt.sa_sigaction = &CGPI::ButtonSignalHandler;
m_actBt.sa_flags = SA_SIGINFO;
sigemptyset(&m_actBt.sa_mask);
err = sigaction(SIGGPIBUTTON, &m_actBt, NULL);

void ButtonSignalHandler(int signum, siginfo_t *info, void *ptr)
{
int data;
printf("Received signal %d\n", signum);
if(signum != SIGGPIBUTTON) return;
data = (int)(info->si_int);
CEvent * evt = new CEvent(data);
evt->id = info->si_uid;
evt->Post(m_evtMgr);
}

In Xenomai (a real time patch for Linux), you have the option to enable kernel rt_task communicate with user space ones using real time message queue (rt_queue_create). I have also tried to get the real time signal working with Xenomai 2.4.91. Xenomai patch only support the RT signals via POSIX skin (officially). However, pthread_sigqueue_np only takes pse51_thread instead of standard POSIX thread, which means the signal can only be sent to Xenomai POSIX skin thread, created by overloaded pthread_create. This is a little messy I know. In non-real time Linux, you have GNU thread and POSIX thread implementations to choose from, or both, depending how you choose to link your libraries. Xenomai has its own implementation of kernel mode finer thread (xnthread_t , if you like to call it). These Xeno threads existing only in Xeno real time domain. When you choose to use native skins, you will be dealing with rt_task_xxx interfaces. However, all the signal handling will just happen in Linux domain. Within POSIX skin, you can queue and set up signal handler for Xeonmai POSIX skin thread. Effectively, instead of using rt_task_xxx, you can use familiar pthread_create APIs. Just bear in mind you need to link to Xenomai libraries.

Friday, August 07, 2009

The ultimate answer to everything in software - upgrade?!

In the last few days, I have been working on a very very nasty problem. To put this into context, I planned to apply one of the existing real time patches to Linux to give us hard real time scheduling performance as opposed to soft real time, which I have briefly explained the difference in my previous blog. I adopted Xenomai 2 to uClinux distribution for Blackfin BF5xx processor using Adeos patch supplied with uClinux2008R1.5 , which is running kernel 2.6.22. Anyway, the problem was, one of our existing GPIO (on I2C bus) driver stops working.

So, after a bit of digging in the code, it appears that the kernel has continuously been trapped within one of the interrupt handler registered by this driver. I should say in this case, the interrupt is in Linux domain. That means, since there is no handling done in Xenomai primary domain and this interrupt is passed by ipipe all the way to Linux non-real time kernel to handle. The problem is, it worked fine when we did not have real time patch in between. In this instance, google did not help either - no obvious answer. I decided to ask for help in Blackfin-uClinux forum and also Xenomai help as people are quite helpful there usually, if you are asking something which has been asked before or known issues. Since this seems to be an outlier, I did not get much out of it, until the author of the patch responded. In short, his answer was that the version I used is a legacy version (2.4.0), unless I upgrade to the latest and greatest xenomai version and uClinux distribution which does not use threaded IRQ anymore, I am pretty much on my own. Right, so first thought came to my mind is that I am busted. It is not a trivial task to port a heavily modified kernel distribution to another version, let alone Linux does not really maintain backward compatibility that well. Anyway, I was stuck between rock and hard place.

So I started to dig into the ipipe to see what is the difference. Unfortunately, the only thing I can see is a positive sign, where the interrupt has been much reliable triggered with smaller amount of latency. Bear this in mind, I have to bet my money on Blackfin implementation at this point. So I went back to check the hardware reference for the type of processor I am using and found out the following:

“When using either rising or falling edge-triggered interrupts, the interrupt condition must be cleared each time a corresponding interrupt is serviced by writing 0x01 to the appropriate bit in the GPIO clear register.”

Right now I have all the pieces of the puzzle. The problem was that the original driver code did not explicitly clear out the GPI pin we configured for interrupt edge triggering, relying on kernel peripheral to clear out resource its allocated after interrupt being served. With Xenomai patched, the interrupt comes quicker to the point before work to be finished (previous interrupt status to be cleared out), the next interrupt kicks in (passed by ipipe). Hence the kernel stuck in this particular ISR. Fix itself is easy enough, one line change to clear the port interrupt register.

What makes me think, however, is that how we normally deal with unknown issues in our system when it comes to software release. Of course there are times that to find out the root cause of A problem would be expensive, which could also become a major distraction from current development undertaking. Unfortunately, from my own experience, many organisations choose to take the altitude to offer system upgrade as a silver bullet when customer has legacy system upon which problems were reported and then pray for those problems to go away on the newer version of release. "Obviously, there are so much we do not know about this world, this problem might just be one of these we could not explain or completely out of our leads, or not worth spending our efforts on. I can to certain degree try to justify if it was for the last reason as we all know sometimes we need to make a balanced decision about where precious resource (as always) should be spent on.

As you can clearly see, the suggestion I was offered as threaded IRQ is a complete wrong shot. Unfortunately, we do blind shot a lot. Question is, have you done this before?

Thursday, May 14, 2009

Linux real time kernel scheduling

While I am working on a real time design on TCP/IP protocol stack, I have the chance to clear the thread of real time scheduling capability on Linux 2.6 kernel and its variants. With O(1) scheduling and real time priority (0 - 99) task and scheduling policy support, standard Linux 2.6 kernel offers soft real time scheduling capability. The defer of the bottom half of interrupt also minimises the interference (delay) to scheduler via softirq and tasklet. I really like the double priority list (active and expired) design in the runqueue where the O(1) scheduling comes from and time slicing calculation, independent to the number of process in the run queue (and wait queue).


There is a hardcore test to prove Ingo's contribution. There are many detailed analysis of Real time Linux patch. This patch is maintained by Ingo Molnar, who is responsible for many other nice features in 2.6 kernel including O(1) priority and time slice calculation, CFS scheduler etc. In a nutshell, RT patch implemented both hard and soft interrupt service function as tasks. Hence instead of running in separate interrupt context, they will be running in kernel task context. RT patch also changed the spinlock from disabling preemption to mutex and introduce localised critical section. Priority inheritance is used to resolve the typical priority inversion problem. Again, this patch is known providing soft real time scheduling, with the best efforts.

RTAI:

RTAI (Real-Time Application Interface) is a real-time extension for the Linux kernel. It supports several architectures:
  • x86 (with and without FPU and TSC)
  • x86-64
  • PowerPC
  • ARM (StrongARM; ARM7: clps711x-family, Cirrus Logic EP7xxx, CS89712, PXA25x)
  • MIPS
RTAI provides deterministic response to interrupts, POSIX compliant and native RTAI real-time tasks. It consists mainly of two parts:
  • An Adeos-based patch to the Linux kernel which introduces a HAL (hardware abstraction layer)
  • A broad variety of services which make real-time programmers' lives easier. RTAI does provide implementations for scheduling policies as RMS, and EDF other than the standard ones offered by Linux 2.6 kernel such as SCHED_FIFO, SCHED_RR, SCHED_OTHER (where dynamic priority scheduling is enabled). SCHED_FIFO and SCHED_RR are normally used for real time tasks which are both static priority scheduling and both do not allow lower priority tasks to preempt higher priority ones, even when allocated time slices are exhausted (in SCHED_RR case). RTAI has a finer timer and also introduces a real time (non-blocking) FIFO for deterministic data transfer between tasks. The heart of RTAI implementation is the HAL layer between Linux kernel and different hardware, which makes this layer very much platform-dependent. The other arguable feature introduced by RTAI is allowing user space tasks to be scheduled via LXRT interface to achieve hard real time performance. It was reported that RTAI is integrated most desirable with Vanilla kernel (2.6.19).
  • Here is a good example project to start from. If you wish to carry out a quantative comparison of how much boost RTAI brings to you, this post gives a few bench mark measurements. Just in case, I put the installation guide here as well. To port your existing Linux programs to take advantage of RTAI, you might want to start from LXRT APIs. At last, if you want a quick summary to take away, here is your PPT. With a worse case report at 48 us scheduling latency and jitter in the range of 10's microseconds on its LXRT branch, RTAI is my favorite.
Xenomai:
Originally from RTAI/fusion branch, Xenomai focuses on extensibility, portability, and maintainability while RTAI is focused on performance such as real time scheduling, latencies, etc. A good comparison article could be found here.

Supported architectures are:
  • x86: from i386 to latest Pentiums and AMD's, UP and SMP
  • x86_64
  • PowercPC (follows DENX tree):
  • Freescale family: PowerQUICC I, PowerQUICC II, PowerQUICC III, ..
  • AMCC family: 405, 440, ..
  • PowercPC 64 (follows DENX tree):
  • PA6T
  • IA64 (discontinued since v2.5)
  • ARM cores:
  • Integrator/CP ARM 1136
  • PXA
  • SA1100-based
  • Freescale iMX21/csb535fs
  • Atmel at91rm9200 (tested on CSB637)
  • Samsung S3C24xx
  • Intel ixp4xx
  • Atmel at91sam926x
  • Motorola i.MX family
  • Analog Devices Blackfin BF52x, BF53x, BF54x and BF56x
I do like the robot project from Hannover. A good serial port driver comparison between RTAI and Xenomai is available on Capitain. The other major focus of the Xenomai project is to help creating emulators of traditional RTOS APIs that ease the migration from these systems to a GNU/Linux-based real-time environment. As of now, the following real-time interfaces
are available:
  • pSOS+ emulator
  • VRTXsa emulator
  • VxWorks emulator
  • uITRON implementation
I could really see Xenomai playing an interesting role in the real time virtulisation applications rather than providing powerful generic emulation interfaces for multiple RTOSes. Minute virtual machine in Xenomai comes with a graphical debugger named Xenoscope that allows tracing the execution of real-time software at source code level in a simulated environment. This tool shows precisely how the multiple threads running in the system work together sharing the resources of a given real-time interface (e.g. who is locking a semaphore, which thread has been readied or suspended by a given system call, and so on).

-------------------------
- Real time application  -
-------------------------
-     RTOS emulators     -
-------------------------
-  Xenomai nanokernel  -
-------------------------
-   Host software arch    -
-      (e.g. RTAI-x86)      -
-------------------------

RTLinux (To be updated)