Prevent your OpenBSD shared-memory objects from being axed by daily(8)
Everything is a file, so I could have known. After about a week running continuously — and flawlessly — my shared-memory object seemed to disappear. Existing processes were happily using it, but new processes were waved off with an ENOENT error: no such file or directory.
It needs to go somewhere…
There is not a word about it on the OpenBSD man page for managing shared-memory objects, but you can guess that in the back, a file is created. shm_open(3) wants a path name; it returns a file descriptor; you close it with close(2); and after all, everything is a file.
The source shows it: shm_open creates a .shm-file, named as the SHA-256 hash of the shared-memory object's path name, and located in /tmp/.
You would expect to be able to use a shared-memory object for an indefinite time, as long as it is not closed and destroyed. After all, there is no expiration time on shared-memory objects. But there is on temporary files.
File access and modification times of shared-memory files do not get updated, no matter whether they are dormant for prolonged periods of time, or used intensively. The culprit behind the inaccessible — and actually removed files — is OpenBSD's daily system maintenance script. It takes out all files, except a few explicitly named ones, in /tmp/ that have not been accessed for seven days. And trashes your shared-memory object.
So what to do? You could re-create the shared-memory object regularly, but that does not sound like a good idea. After all, there are various processess working on it. You could change /etc/daily and put in another exception, protecting all .shm files, or at least the one you want to be respected (being a hash, the random-looking 'temporary' filename is deterministic from the chosen path name). But changing daily is discouraged and will not survive a system upgrade. You could change shm_open.c and build your own kernel — even worse.
The easiest way is to touch your file regularly. You can create a cron job for this, refreshing file times twice a week, for example. But in my case, I have a daemon process that works on the shared-memory object at short intervals anyway, so I added a daily call to futimes(shmfd, NULL), in which shmfd is the file descriptor to the shared-memory object.
By the way: semaphores are created the same way. A semaphore is in fact a shared-memory objects with a SHA-256 filename in /tmp/, containing a few integers and pointers. They will probably suffer the same fate. So while I was at it, I created my own semaphore to synchronise access to the shared memory. It requires remarkably simple functionality, for which standard semaphores seem rather excessive in hindsight. But that's for another post.