Your problem may be elsewhere.
Edit: This may be a shmmni
limit of macOS. See below.
When I run your [simplified] code on my system (linux), the shmget
fails.
You didn't specify IPC_CREAT
to the third argument. If another process has created the segment, this may be okay.
But, it doesn't/shouldn't like a size of 0. The [linux] man page states that it returns an error (errno
set to EINVAL) if the size is less than SHMMIN
(which is 1).
That is what happened on my system. So, I adjusted the code to use a size of 1.
This was done [as I mentioned] on linux.
macOS may allow a size of 0, even if that doesn't make practical sense. (e.g.) It may round it up to a page size.
For shmat
, it returns (void *) -1
.
But, some systems can have valid addresses that have the high bit set. (e.g.) 0xFFE0000000000000 is a valid address, but would fail your if
test because casting that to int64_t
will test negative.
Better to do:
if ((int64_t) *ptr == (int64_t) -1)
Or [possibly better]:
if ((void *) *ptr == (void *) -1)
Note that errno
is not set/changed if the call succeeds.
To verify this, do: errno = 0
before the shmat
call. If perror
says "Success", then the shmat
is okay. And, your current test needs to be adjusted as above--I'd do that change regardless.
You could also do (e.g):
printf("ptr=%p\n",*ptr);
Normally, errno
starts as 0.
Note that there are some differences between macOS and linux.
So, if errno
is ever set to "too many open files", this can be because the process has too many open files (EMFILE
).
It might be because the system-wide limit is reached (ENFILE
) but that is "file table overflow".
Note that under linux shmat
can not generate EMFILE
. However, it appears that under macOS it can.
However, if the number of calls to shmat
is limited [as you mention], the shmat
should succeed.
The macOS man page is a little vague as to what the limit is based on. However, I checked the FreeBSD
man page for shmat
and that says it is limited by the sysctl
parameter: kern.ipc.shmseg
. Your grep
should have caught that [if applicable].
It is possible some other syscall elsewhere in the code is opening too many files. And, that syscall is not checking the error return.
Again, I realize you're running macOS
.
But, if available, you may want to try your program under linux. For example, it has much larger limits from the sysctl
:
kernel.shm_next_id = -1
kernel.shm_rmid_forced = 0
kernel.shmall = 18446744073692774399
kernel.shmmax = 18446744073692774399
kernel.shmmni = 4096
vm.hugetlb_shm_group = 0
Note that shmmni
is the system-wide maximum number of shared memory segments.
Note that for macOS
, shmmni
is 32 (vs. 4096 for linux)!?!?
That means that the entire system can only have 32 open shared memory segments for any/all processes???
That seems very low. You can probably set this to a larger number and see if that helps.
Linux has the strace
program and you could use it to monitor the syscalls.
But, macOS has dtruss
: How to trace system calls of a program in Mac OS X?