问题描述
QNX系统中 Client 与 Server 通过 QNX Message Passing 进行进程间通信。正式开发前,写过测试程序 (Client),和 Server 通信一切正常。但把同样的代码拷贝到正式的 Client 中,结果发现调用 MsgSend() 后无响应,pidin 显示 Client 处于 REPLY PENDING 的状态。
几番尝试,发现一个让人很难接受的事实:只能在 Client 的主线程中调用 MsgSend() 才能收到 Server 的回复,如果在 Client 的对等线程中调用MsgSend(),则会因为收不到 Server 的回复而 Pending。
问题分析
测试程序能正常工作,所以起初怀疑是 Client 的问题。面对庞大的 Client,始终没想到突破口。甚至曾一度怀疑是否是 QNX 的系统限制,MsgSend() 只能在主线程中调用,官网文档翻了一圈并没有发现这样的限制。自己写了个 IPC Server 来测试,发现并没有这个问题。
Client | Server | 结果 |
测试程序,主线程中调用 MsgSend() | 正式 Server | OK |
正式 Client,对等线程中调用 MsgSend() | 正式 Server | REPLY PENDING |
正式 Client,对等线程中调用 MsgSend() | 简化版测试 Server | OK |
最后不得不怀疑起 Server,莫非 Server 端有什么机制能检测到消息是发自主线程还是对等线程,然后只回复来自主线程的 IPC 请求?
一个典型的 IPC Server 示例代码如下:
While(1) { int rcvid = MsgReceive(chid, &recvBuf, sizeof(recvBuf), NULL); /* … process the request based on recvBuf … */ MsgReply(rcvid, EOK, &replyBuf, sizeof(replyBuf)); // reply to unblock the IPC client }
如果是从 Client 的主线程发送来的消息,rcvid 是一个很小的数字,如 1, 3, 5… 如果是从Client 的对等线程发送来的消息,rcvid 是一个大于 65535 的数字,如 65538, 65540, 65542…
让人意外的是 Server 用了一个 int16_t 来保存 rcvid,直接导致后续的 MsgReply() 无法正确的将消息回给 Client,从而导致 Client 一直处于 REPLY PENDING 状态。
Reference
- http://www.qnx.com/developers/docs/7.0.0/#com.qnx.doc.neutrino.sys_arch/topic/ipc_Robust.html