You shall not slay the client

· January 31, 2022

Report a bug

Recently, I got the opportunity to attend a two-week-long training in Real-Time Programming For QNX Neutrino RTOS where I am learning the ins and outs of QNX, a real-time microkernel operating system that is a UNIX-like OS. On one of the demos, the trainer showed us a behavior that I thought was impossible. This shook the foundation of my understanding of IPC (Inter-Process Communication) and on signals. However, this is a feature in QNX that does not exist on Linux from my understanding.

The demonstration involved a client and server communicating with each other. Nothing out of the ordinary with the exception that the client is REPLY blocked. At this state, the client is blocked and is waiting for the server to reply back either with a message or an error. If the server sets the flag _NTO_CHF_UNBLOCK during the creation of the channel. In QNX Neutrino, threads communicate on a channel or on a connection whereby one thread (i.e. the server) will initiate a channel and have the other thread (i.e. client) “connect” to the channel by attaching to the channel. (On a side tangent, my brief introduction to QNX IPC makes me jealous). When the server creates a channel ChannelCreate(), it can pass a flag _NTO_CHF_UNBLOCK whereby it can stop the client from unblocking itself (such as to respond to a signal).

This says to the kernel, “Tell me when a client tries to unblock from me (by sending me a pulse), but don’t let the client unblock! I’ll unblock the client myself.”

The key thing to keep in mind is that this server flag changes the behavior of the client by not allowing the client to unblock until the server says it’s okay to do so. Getting Started with QNX Neutrino - _NTO_CHF_UNBLOCK

Therefore, any signals set onto the client becomes pending and the client remains blocked. This includes SIGKILL and SIGTERM, which is very worrisome. The purpose of this feature has merit and is well explained in the documentation but the fact it can still stop SIGKILL and SIGTERM is something unexpected for those of us new to QNX and come from Linux.

From the realm of Linux, signals can be blocked but SIGKILL and SIGTERM are definitely not one of them as seen from the man pages (man 7 signal):

$ man 7 signal | grep "SIGKILL and SIGSTOP"
       The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.

The reason why this is worrisome is the fact that you cannot kill a misbehaving thread which is often the case during development. You would be required to either have the server respond to the misbehaving thread in a timingly manner or kill the server itself to kill the client. This would cause panic to anyone not familiar with QNX as my trainer noted during the session where clients would call for technical support. You can also see similar questions arising in forums such as this.

It also doesn’t help that the documentation for QNX 7.1 states that SIGKILL cannot be blocked or caught. But with _NTO_CHF_UNBLOCK, you could block the signal (the server creating the channel with this flag cannot ignore it though). Perhaps it would be helpful to add an asterik to state there are some exceptions but that’s just my opinion. POSIX standards from my interpretation does not state anything against blocking a SIGKILL. The POSIX Standard (IEEE Std 1003.1-2017) states that Kill (cannot be caught or ignored). but nothing about being blocked.

Conclusion

In summary, do not expect the behaviors of how signals work on Linux (or your preferred POSIX OS) to apply to all other POSIX compliant Operating Systems. QNX allows a server during channel creation to specify _NTO_CHF_UNBLOCK to prevent clients from unblocking and even blocks SIGTERM and SIGKILL.

ps: slay is a QNX utility to kill or send a signal to a process (Hence the title)

Twitter, Facebook