QNX 4 provided something called a proxy. A proxy is best described as a canned (or fixed) message, which could be sent by processes or kernel services (like a timer or interrupt service routine) to the owner of the proxy. The proxy is non-blocking for the sender and would arrive just like any other message. The way to identify a proxy (as opposed to another process actually sending a message) was to either look at the proxy message contents (not 100% reliable, as a process could send something that looked like the contents of the proxy) or to examine the process ID associated with the message. If the process ID of the message was the same as the proxy ID, then you could be assured it was a proxy, because proxy IDs and process IDs were taken from the same pool of numbers (there'd be no overlap).
QNX Neutrino extends the concept of proxies with pulses. Pulses are still non-blocking messages, they can still be sent from a thread to another thread, or from a kernel service (like the timer and ISR mentioned above for proxies) to a thread. The differences are that while proxies were of fixed-content, QNX Neutrino pulses are fixed-length, but the content can be set by the sender of the pulse at any time. For example, an ISR could save away a key piece of data into the pulse and then send that to a thread.
Under QNX 4, some services were able to deliver a signal or a proxy, while other services were able to deliver only one or the other. To complicate matters, the delivery of these services was usually done in several different ways. For example, to deliver a signal, you'd have to use the kill() function. To deliver a proxy or signal as a result of a timer, you'd have to use a negative signal number (to indicate it was a proxy) or a positive signal number (to indicate it was a signal). Finally, an ISR could deliver only a proxy.
Under QNX Neutrino this was abstracted into an extension of the POSIX struct sigevent data structure. Anything that used or returned the struct sigevent structure can use a signal or a pulse.
In fact, this has been extended further, in that the struct sigevent can even cause a thread to be created! We talked about this in the Clocks, Timers, and Getting a Kick Every So Often chapter (under Getting notified with a thread).