How do you correctly cleanup and re-use SysV shared memory segments?
I was misled into thinking it was proper form to call shmctl(segmentId, IPC_RMID) as soon as the process designated as the owner has attached to the shared memory.
In fact IPC_RMID should not be called until all processes have attached.
Part of the answer is here:
https://comp.unix.programmer.narkive.com/iLg3PhfZ/shmctl-ipc-rmid-oddity
It seems that IPC_RMID sets the segment to private so that no new processes can attach to it.
A way of guaranteeing a unique segment is deliberately using IPC_PRIVATE to start with:
id = shmget(IPC_PRIVATE, IPC_CREAT | mode);
This also avoids the need to use ftok() and risk colliding with another segment.
Unfortunately I cannot use that here as the interface is predicated on identifying the segment with ftok(). At least I understand the issue here.
Someone wiser may be able to chip in with better ways of cleaning up before re-use.
See also https://www.linuxquestions.org/questions/programming-9/shmctl-ipc_rmid-precludes-further-attachments-574636/
Also consider this question and answer: Linux IPC: shared memory recovery
Deleting shared memory segment with shmctl
Your first reasoning is correct. The shared segment will exists until both: it is marked with IPC_RMID
and last process detaches.
The purpose of the second fragment is to remind you, that in a solution using shared memory you need to have some process mark it for destruction or it will remain in memory/swap forever. It might be good idea to use IPC_RMID
immediately after creating segment.
If you are not sure you have successfully released memory, you can use ipcs
program to list remaining segments.
Relationship between shared memory and files
The path given to ftok is just a placeholder in the "everything is a file" tradition.
After some time considering I would say mmap is a simpler, safer and more effective API. I personally would avoid shmget etc. completely if possible.
It is particularly awkward to clean up after shmget() see:
- Linux IPC: shared memory recovery
See also:
- Linux shared memory: shmget() vs mmap()?
- System V IPC vs POSIX IPC
- How do you correctly cleanup and re-use SysV shared memory segments?
An argument used in favour of system-v in one of the linked questions is that Posix was less widely implemented. I don't know if that was true then but it seems even less likely to be true now. Given the dominance of GNU/Linux & BSD derivatives. Even the legendarily 'unique' AIX claims Posix compliance these days.
Linux IPC: shared memory recovery
It might be better idea to alter your producer design:
Instead of using IPC_CREAT it could first check if there is an existing segment that could be re-used.
You could also consider using mmap based shared memory instead which is more flexible in some ways.
You could use some other indicator such as a lock file to determine if the shared memory interface is still viable.
However, if for some reason these are not options (someone else controls the producer code for example) then read on.
There are several things you can do:
- use shmctl() to 'stat' your memory segment
// return true if the shared memory region is still 'useful/useable'
bool checkShm(int shmId)
{
struct shmid_ds statBuf;
int res = shmctl(<shmid>, IPC_STAT, statBuf);
if (res == -1) return false;
...
- check if the region is marked for deletion (Linux specific)
if ((statBuf.shm_perm.mode&SHM_DEST) != 0) return false;
- assuming you attached after the producer and it is the creator process - check that it dettached after you.
caveat: It could have reattached again if your design allows this.
if (statBuf.shm_cpid == shmBuf.shm_lpid) return false;
- check the PID of the creator process is a running process.
caveat: the PID could be recycled by a new process
if (getpgid(shmBuf.shm_cpid) == -1) return false;
note: you could use kill(shmBuf.shm_cpid,0)
instead if the producer is not a different user.
- You might also want to check if the file has been modified.
A key point is that ftok uses the inode number not the actual filename as the man page suggests. So you need to be careful using it:
struct stat fstatBuf;
int res = stat(fileName,&fstatBuf);
if (res == -1) return false; // if the file has disappeared it could be a bad sign!
if (fstatBuf.st_ino != savedInode) return false;
Having done all this you should now have a reasonably good way to check if the SHM you think is still useful is actually being used by the 'producer' you think it is.
- Clean up the stale shared memory segmant
You are now free to detach shmdt() from the segment, and try to clean it up shmctl(shmid,IPC_RMID,NULL). The consumer process might not have permissions to remove it if the creator did not grant them.
- Attach to the replacement shared memory segment
You are then in principle able to attach to any new shared memory segment created by a replacement producer process:
auto key = ftok(<somefile>,<someid>;
void* memArea = shmat(key,NULL,0);
// check errors and do stuff...
But there a cruel and interesting punishment awaits you. It will not work immediately. You have to wait a time and periodically retry. I guess this is until the operating system has had a chance to clean up the old memory segment.
I found that ftok() returns -1 for a while despite the file existing and having the same inode as the original file.
Remove posix shared memory when not in use?
No - at lest on Linux, the kernel doesn't contain anything that can do this. It's up to some application to call shm_unlink() at some point to get rid of a shared memory segment.
Related Topics
Interprocess Communication Using Pipe in Linux
How to Get a List of Programs Running with Nohup
Skipping Acquire of Configured File 'Main/Binary-I386/Packages'
How to Resume Interrupted Download Automatically in Curl
Rm Fails to Delete Files by Wildcard from a Script, But Works from a Shell Prompt
How to Determine If Lcd Monitor Is Turned on from Linux Command Line
Linux - Yum Install Gcc - Missing Kernel-Headers
What Is the Access Time in Unix
Linux Kernel Interrupt Handler Mutex Protection
What Does the Mkdir -P Mean in a Script File
How to Delete Multiple Files at Once in Bash on Linux
Difference Between Unix Domain Stream and Datagram Sockets
Adding Any Current Directory './' to the Search Path in Linux
Remove the Last Page of a PDF File Using PDFtk
Setting Node_Env for Node.Js + Expressjs Application as a Daemon Under Ubuntu