How to close/clear an IPC message queue? - c

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.

Related

What to do when done using POSIX QUEUE

I am using mqueue.h to use POSIX message queue to communicate between threads (for school project demonstration).
When I am done with my two pthreads using the queue and want to close the message queue, what should I do?
Do mq_unlink and mq_close from both threads
Do mq_unlink and mq_close from one thread
Only do mq_unlink from one thread
Only do mq_unlink from two threads
Only do mq_close from one thread
Only do mq_close from two threads
Edit (because of): "Closed. This question needs details or clarity"
I am using a POSIX message queue defined in mqueue.h (C) to send messages between threads. This is similar to interprocess communication with a message queue. I could communicate using the shared memory but that is not what I want to do. I have created, opened, sent and received messages between threads successfully but need to know what to do when done. I have found mq_close and mq_unlink but have not found information about how they should be used and from where. That is what I am asking about.
mq_overview - overview of POSIX message queues.
Similar like dealing with files.
Call mq_close on each mq_open.
When a process has finished using the queue, it closes it using mq_close(3), and when the queue is no longer required, it can be deleted using mq_unlink(3).
Call once mq_unlink optionally.
POSIX message queues have kernel persistence: if not removed by mq_unlink(3), a message queue will exist until the system is shut down.
mq_unlink() removes the specified message queue name. The message queue name is removed immediately. The queue itself is destroyed once any other processes that have the queue open close their descriptors referring to the queue.

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

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.

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.

How to cleanly interrupt a thread blocking on a recv call?

I have a multithreaded server written in C, with each client thread looking something like this:
ssize_t n;
struct request request;
// Main loop: receive requests from the client and send responses.
while(running && (n = recv(sockfd, &request, sizeof(request), 0)) == sizeof(request)) {
// Process request and send response.
}
if(n == -1)
perror("Error receiving request from client");
else if(n != sizeof(act))
fprintf(stderr, "Error receiving request from client: Incomplete data\n");
// Clean-up code.
At some point, a client meets a certain criteria where it must be disconnected. If the client is regularly sending requests, this is fine because it can be informed of the disconnection in the responses; However sometimes the clients take a long time to send a request, so the client threads end up blocking in the recv call, and the client does not get disconnected until the next request/response.
Is there a clean way to disconnect the client from another thread while the client thread is blocking in the recv call? I tried close(sockfd) but that causes the error Error receiving request from client: Bad file descriptor to occur, which really isn't accurate.
Alternatively, is there a better way for me to be handling errors here?
So you have at least these possibilities:
(1) pthread_kill will blow the thread out of recv with errno == EINTR and you can clean up and exit the thread on your own. Some people think this is nasty. Depends, really.
(2) Make your client socket(s) non-blocking and use select to wait on input for a specific period of time before checking if a switch used between the threads has been set to indicated they should shut down.
(3) In combo with (2) have each thread share a pipe with the master thread. Add it to the select. If it becomes readable and contains a shutdonw request, the thread shuts itself down.
(4) Look into the pthread_cancel mechanism if none of the above (or variations thereof) do not meet your needs.
Shutdown the socket for input from another thread. That will cause the reading thread to receive an EOS, which should cause it to close the socket and terminate if it is correctly written.
To interrupt the thread, make the socket non-blocking (set O_NONBLOCK using fcntl) and then signal the thread with pthread_kill. This way, recv will fail with either EINTR if it was sleeping, or EAGAIN or EWOULDBLOCK if it wasn’t (also maybe if SA_RESTART is in effect, didn’t check). Note that the socket doesn’t need to, and actually should not, be non-blocking before that. (And of course the signal needs to be handled; empty handler is sufficient).
To be sure to catch the stop-signal but not anything else, use a flag; there are things that may go wrong. For example, recv may fail with EINTR on some spurious signal. Or it may succeed if there was some data available, effectively ignoring the stop request.
And what not to do:
Don’t use pthread_kill alone or with any plain check. It may arrive right before issuing the recv syscall, too early to interrupt it but after all the checks.
Don’t close the socket. That may not even work, and as #R.. pointer out, is dangerous as the socket file descriptor may be reused between close and recv (unless you’re sure nothing opens file descriptors).

executing threads in POSIX

I am creating an asynchronous chat application in C. I created two threads, one for receiving and another one for sending as follows.
void* send()
{
...
}
void* receive()
{
...
}
main()
{
..
inid = pthread_create(&incoming,NULL,receive,"Incoming thread");
outid= pthread_create(&outgoing,NULL,send,"Outgoing thread");
..
pthread_join(incoming,NULL);
pthread_join(outgoing,NULL);
..
}
What the problem is, the send and receive functions are called only once and the program terminates. I want both the threads to run forever till the user wishes to exit ( the condition to check for exit is defined in the send function). How to solve this?
One solution is to have a while(input != exit) type of loop in send.
And make your main to only wait for outgoing thread (which means having pthread_join only for outgoing thread). So, when the user chooses to exit, the main will exit without waiting for the incoming thread.
Secondly, you need to use a blocking receive function in the receive function. So, it is either processing an incoming message or waiting for one.
Another solution is to have a while(input != exit) type of loop in main. Have a message queue defined in which main can queue messages to be sent and the outgoing thread consumes messages from this thread to actually send them.
The outgoing thread is either sending a message or is blocked until the queue has a message in it to be sent.
The input thread behaves in the same way as described in the previous solution.

Resources