Home > Software design >  How to close/clear an IPC message queue?
How to close/clear an IPC message queue?

Time:10-21

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;
    }

CodePudding user response:

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

  1. clearing the queue doesn't actually do much for resource usage, and
  2. 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