Is it possible to send signals through IPC Message Passing Queue? - c

I have tried calling kill from process A to process B and the process B has successful reacted to the signal. The problem is I don't want to send signals from the kill function directly for two reasons:
1) Sometimes the process A may not have the permissions, ex. process B is ran by another user
2) I want to be able to send signals from A to B through the message queue
I am creating a message queue from which I send "objects" of the following structure
typedef struct msg {
long message_type;
char message_text[SIZE];
}message;
I want to know if it is possible for process A to signal B through IPC Message Passing. I know I can achieve this by sending the signal type into the message_text from process A to B and then inside the process B check the type of the signal and act properly but I was wondering if there is another way.
Would this be possible by passing sigaction objects as messages:
struct sigaction as;
//...
msgsnd(queue_id, &as, length, IPC_NOWAIT);
//...
I know this is completely infeasible but this is what I am trying to achieve. Thank you

Based upon your comments it seems that you want B to be able to receive messages but when it receives a "signal" message it needs to act like it received a regular signal. You mentioned that the B needed to react to SIGTERM or SIGINT from the "signal" message.
The way to achieve this is depends upon using POSIX message queues or System V message queues.
Either way it doesn't seem that you want to use polling of the message queue by the main thread of B as that would add to much latency to responding to the "signal" message.
So with POSIX message queues you can use mq_notify() to run either a thread or raise a signal that a new message has arrived. Otherwise B can use a thread (or even fork()) to poll the message queue.
After a "signal" message is received you have a couple of options. A) You can use either kill or raise in B to send a signal of the correct type to itself (or parent in case of fork), or B) just call a function that does what you want (that sort of thing).
Process A can send a "signal" message whenever it wants. But you need to understand that if you are using named queues they are persistent. That is that A can send a "signal" message before B even starts, and then when B starts that message is waiting there. Depending on how the message queue is made it can be N messages deep and have older messages in the queue. One way to deal with that is for B to empty the queue before processing any of the messages.

Message queues can’t achieve how signals do. With signal it is possible to asynchronously interrupt or kill process but with message queue when receiving process checks message or wait on it and exits after receiving message, it actually will ignore that message rest of path of execution(synchronous). But, It is possible to achieve with threads.

If you were using a POSIX message queues (using mq_send/mq_receive), then process B can request (with mq_notify) to be sent a signal every time a message is sent to the message queue. However, your example seems to be using a SYSV legacy message queue (msgsnd) which does not suppport any kind of notify.

Related

How to close/clear an IPC message queue?

I have this call in the cleanup of the main thread of process_B which receives messages on an IPC message queue:
if (msgctl(qId, IPC_RMID, NULL) < 0) {
perror("msgctl");
}
And when reached, reports the following:
msgctl : Invalid argument
Error: failed to remove message queue.
I have another process_A, which sends messages to process_B and isn't being shutdown.
Then there's this statement in man msgctl ...
IPC_RMID
Immediately remove the message queue, awakening all waiting
reader and writer processes (with an error return and errno set
to EIDRM). The calling process must have appropriate privileges
or its effective user ID must be either that of the creator or
owner of the message queue. The third argument to msgctl() is
ignored in this case.
I'm not clear on how removing the message queue awakens all readers and writers. Does process_A have to somehow close as well before process_B can remove the message queue?
If process_B closes, I'm trying to cleanup the resources to include this message queue. And if it is restarted, I'd like for process_B to "reconnect" to the message queue after having cleared the queue in the case that process_A was never shutdown. Is clearing the queue possible? And then of course I'd do the same for process_A.
Update: (adding the opening of the message queue):
key_t key = ftok(".", 'm');
int qid = msgget(key, IPC_CREAT | 0644);
if (qid == -1) {
perror("msgget");
return -1;
}
I have this call in the cleanup of the main thread of process_B which
receives messages on an IPC message queue:
if (msgctl(qId, IPC_RMID, NULL) < 0) {
perror("msgctl");
}
And when reached, reports the following:
msgctl : Invalid argument
Error: failed to remove message queue.
The "Error:" message must be from some other code not in evidence, but the "msgctl :" message appears to be output from perror(), reporting on an EINVAL. For an IPC_RMID command, that indicates that the queue ID passed to the function was invalid. Perhaps that queue had already been removed?
I'm not clear on how removing the message queue awakens all readers and writers. Does process_A have to somehow close as well before process_B can remove the message queue?
Removing the queue awakens all waiting readers and writers. That is, those that are currently blocked trying to send messages to the queue or receive messages from it. The docs are simply saying that those calls will stop blocking, and instead fail (returning -1) with errno set to EIDRM. So no, process_A does not have to terminate or perform any other action before process_B can remove the queue.
HOWEVER,
If process_B closes, I'm trying to cleanup the resources to include
this message queue.
Ok so far.
And if it is restarted, I'd like for process_B to
"reconnect" to the message queue after having cleared the queue in the
case that process_A was never shutdown.
I think you're not appreciating what it means to remove the queue. After successfully removing it, there is nothing left to reconnect to. You must instead create a new queue, and somehow get all processes involved to attach to and use that queue. It may well have a different queue ID (albeit obtained via the same key).
Is clearing the queue
possible? And then of course I'd do the same for process_A.
You can clear the queue without removing it by preventing all processes from sending new messages (via a process-shared mutex or semaphore) and then receiving all the available messages. Don't forget to provide for the mutex / semaphore to be released.
However, I urge you to think about your strategy here. If you simply clear the queue without removing it, then nothing prevents process_A from sending more messages to the queue while there is no process_B running, so
clearing the queue doesn't actually do much for resource usage, and
you need to think about what a new process_B will do with messages sent before it started execution.
Similar applies for the reverse direction.
Also, remember that System V message queues have kernel persistence, so their lifetime is not tied to that of any particular process. SysV MQs will live from their creation to their explicit removal, or until the system shuts down, whichever comes first.

Sending same data to two different thread using message queue (single message queue) in C

Is to possible to send the same data from sender thread to two different receiver threads using message Queue mechanism. Receiver thread should receive same data. As per my understanding Shared memory with synchronization mechanism is proper solution for such scenario. But I was wondering if we could do it using message queue as if one thread pop the data other thread won't have anything to receive from the system message queue.

Is there a way to send EOF to the process reading a message queue?

I have one process sending data through a message queue with msgsnd. Another process reading from the queue with msgrcv. The reading process needs to wait until it has all messages before it can continue. How can I tell it that all messages have been sent?
The way I've been doing it is after the sender has sent all its messages it then checks the number of messages in the queue in a while loop. When there are no more messages it closes the queue.
That tells the reading process to continue doing other things. This doesn't seem very reliable though. Many time the sending process will get stuck in an infinite loop of checking the queue status.
Is there a way for me to just send an EOF message and have the reading process watch for that? Then I could just send EOF and have the sending process exit.
Normally the receiver notices that the sender has finished sending because it tries to receive the next message and the receive call indicates that there was nothing left to receive. With communication through file descriptors (pipes, sockets), closing the is how you “send EOF”, and the read call returns 0 bytes. With message queues, it's a little different, because they are message-based rather than streams and there are often multiple senders.
You can call msgctl with the command IPC_RMID. This causes any waiting or subsequent call to msgrcv (or msgsnd) to return -EIDRM (-EINVAL on some BSD systems). The problem with this approach is that there may be messages pending in the queue that the receiver has not read yet and will thus we lost.
Instead, when the sender has nothing else to, have it send a message onto the queue that says “I'm finished”. In the receiver, when you receive this message, remove the queue. This works well when you use the queue between threads of one process. If there are multiple processes, the sender could die without having send the termination message.
How to handle the multi-process case will depend on the structure of your application, and in particular what the reading process wants to do when the sender is dead. One way you can detect this is by having a pipe between the sender and the receiver. Have a thread on the receiver listen on that pipe; if it detects the end of the file, it can
set a variable that is shared with the thread that calls msgrcv;
peek at the queue (msgctl with IPC_STAT);
if the queue is empty (msg_qnum == 0), remove it.

Message Queue - Multiple processes send cmd on a msgqueue

I have a scenario where multiple processes (p1,p2,etc) simultaneously send a command (post) to a msg Queue(cmd_msg_q).
And there is one receiver processes (R1) which retrieves the msg from the queue and send appropriate reply back to the processes on another msg queue ( response_msg_q ).
how to reply from the receiver process so that the message is sent to that particular processes ?
( Using Posix Message queue. ) Here Process A, B or C gets created dynamically. Max limit is 20 process which can send commands.
In that case you'll have to integrate some ID of the sender in the message. Also note that these queues are essentially one-way, so to send messages back you need to create a queue on which the initial receiver will send, and the initial sender will listen for replies.
This is harder to explain than I initially thought, so let's try with and example. Assume we have programs A B and C where A and B send to C. They do so via the same queue. C will know who sent the message because the sender's identification is embedded in the message, and will post the reply to either the queue read by B or the queue read by C.
POSIX message queues pretty much require that you establish a second queue for each process and there is a pretty well establish pattern for this.
Your cmd_msg_q should be an established, well known queue (i.e. the path name). The system can create the queue (e.g. a startup script) before any applications are launched or the receiving process can create it before any sender processes are launched.
Establish a protocol of message types, minimally: (1) open output queue; (2) process message; (3) close output queue. Each message will need to contain an indication of which sender process is submitting the transaction e.g. pid or some unique identifier.
The sender processes create their own queues (e.g. input to them and output to the receiving "command" process. They send an "open queue" message to the receiver along with the path name of the queue they just created. The command process opens the output queue(s) to the receivers and acks that communication is established.
"process" message types are exchanged. The command process reads input from the combined source queue, and replies to appropriate output queue based on the identifier in each message.
Client (receiver) queues send a "close queue" message type when they are done. Command process sends an ack and closes that receiver queue. Client processes the ack and closes it queue.

how to send signal with more information to other threads?

I am programming with pthread in C language. I want a thread to tell other threads that it has put a message on the message queue, so that other threads would know that they can fetch messages from the message queue. However, the thread which has sent the signal should supply more information to other threads, such as thread id, message tag, and so on. How to do that ?
I know pthread_kill function, but It seems take little information. Can I take more information when I use a thread send signal to other threads ?
A signal in the C sense is not able to take "more information" - if you want to send more information, then you need to include that as part of the message in the message_queue, rather than as part of the signal.
I'm pretty sure there are dozens of alternatives. Just that you haven't thought of them. Like I said, if you want to use signals, then use a signal to indicate that there is a message (like the telephone ringing) then use a message queue to convey the actual information (talking on the phone). We don't use the phone ring signal to convey the message over the phone, right?
But I fear that you have somehow misunderstood the usage of threads and signals. I'm pretty sure that the way you are SUPPOSED to solve whatever you ar doing, isn't the right way.
Since your question is "How do I send more than an integer in a signal, I think you should accept Arno's answer, and then try again if that doesn't help - with a description of what your OVERALL problem is that you are trying to solve - right now you are talking to a mechanic about how to losen a bolt, but what you really need to do is fix a puncture, so you may be too concentrated on how to solve the detail, to muss the fact that you haven't even got a jack to lift the car off the ground...
Threads of a process share the same adress space. Thus it is common to build a mutex protected message queue for interthread communication. See this answer to get into the details. The message queue may be a custom design e.g. a linked list structure which may contain elements like sender ThreadID, receiver ThreadID, the message, and optional any number of additional parameters like message state or something. It may also contain a unique message ID and a parameter to tell the receiving thread how to proceed, e.g. remove the message from the queue or not.
A signal can still be used to avoid polling the message queue for new messages. A signal will trigger threads to read the mutex protected message queue for new messages. Another way is to build up an event scheme, as described in this answer. But this is in fact also a mutex protected global identifier which is set and the waiting thread is polling for the change (so called busy wait). Could do the busy wait on the mutex protected message queue right away. See this link for more information about pthread_cond_wait.

Resources