How do I stop sem_open() failing with ENOSYS?

12,663

Solution 1

Is /dev/shm mounted? Older versions of slackware may not have mounted this filesystem at boot. From /etc/fstab:

tmpfs  /dev/shm  tmpfs  defaults  0   0

Edit: That is probably not the problem after all. I think you may just need to upgrade your kernel or maybe even librt.

Edit2: I think that for slackware 11, which I think you are using, you'll need a kernel newer than 2.6.13 to use the NPTL threading libraries (libs in /lib/tls) which appear to be required for the sem_open to work.

Edit3: I managed to get it to work with a slackware 11 box I have by a) mounting /dev/shm and b) setting the environment variable LD_ASSUME_KERNEL to 2.6.13 (any kernel version > 2.6.12 will work). That seems to work even though the kernel is 2.6.11.11, but other things like threads might not.

Solution 2

Older versions of the threading libraries don't support sharing POSIX semaphores between processes. From man sem_init

The pshared argument indicates whether the semaphore is local to the current process ( pshared is zero) or is to be shared between several processes ( pshared is not zero). LinuxThreads currently does not support process-shared semaphores, thus sem_init always returns with error ENOSYS if pshared is not zero.

As sem_open() creates named semaphores, it always tries to share them between processes.

To support sharing anonymous semaphores between processes with sem_init() on Slackware 10

  • upgrade libpthread and (possibly) librt
  • upgrade the kernel

Additionally, to support sharing named semaphores with sem_open()

  • add a line to /etc/fstab to mount /dev/shm as a tmpfs

    tmpfs /dev/shm tmpfs defaults 0 0

  • run mount /dev/shm or reboot

Solution 3

The "process shared sema4s don't work" hypothesis makes some sense to me. Not that it helps you, but if you have time and inclination you might want to try the following, to see whether the "process-shared" aspect is what is failing:

  1. create a semaphore using sem_init in unshared memory (for threads). If it works then sema4s work within the process.

  2. repeat experiment in shared memory. This should tell you if they work between processes. Note that you may need to actually try to USE the sema4 to see whether it works between processes.

Share:
12,663
Kieran Tully
Author by

Kieran Tully

Updated on June 08, 2022

Comments

  • Kieran Tully
    Kieran Tully almost 2 years

    I have two Slackware Linux systems on which the POSIX semaphore sem_open() call fails with errno set to 38. Sample code to reproduce below (the code works fine on CentOS / RedHat).

    Are there any kernel or system configuration options that could cause this? Other suggestions?

    Systems with issue are Slackware 10.1.0 kernel 2.6.11 /lib/librt-2.3.4.so /lib/libpthread-0.10.so, but the same code works on the much older RedHat 9 kernel 2.4.20 /lib/librt-2.3.2.so /lib/tls/libpthread-0.29.so. (and also works on CentOS 5 kernel 2.6.18 /lib/librt-2.5.so /lib/i686/nosegneg/libpthread-2.5.so).

    man sem_open suggests this errno means sem_open() is not supported by system.

    #define ENOSYS          38      /* Function not implemented */
    

    The sem_open() userspace is in librt which we link against dynamically and librt is present on the affected systems.

    The affected system claims to support POSIX semaphores: _POSIX_SEMAPHORES is true and sysconf(_SC_SEMAPHORES) confirms this.

    Thanks, Kieran

    Edit 1: I've added more detail on the software versions in use and removed some irrelevant comments.

    Edit 2: /dev/shm is mounted on the good systems and not mounted on the bad systems. Mounting it did not change the behaviour on the affected systems. I think /dev/shm is necessary too but sem_open() is failing before that, and strace supports this.

    # /* Quick'n'dirty test program to illustrate sem_open failure
    #Run this file to auto-build test and run as a.out
    
    # Build
    gcc $0 -lrt
    if [ $? -ne 0 ] ; then exit ; fi
    
    # Run
    $( dirname $0)/a.out
    exit
    */
    
    #include <stdio.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <unistd.h>
    #include <semaphore.h>
    
    
    int main(int argc, char *argv[]) {
    
     const char *SEM_NAME = "SHRMEM_SCXL";  /* name of mutex */
     sem_t *mutex = SEM_FAILED;             /* ptr to mutex */
    
    #ifdef _POSIX_SEMAPHORES
      printf("_POSIX_SEMAPHORES %ld\n", _POSIX_SEMAPHORES);
    #else
      puts("Undefined");
    #endif
    
     printf("sysconf %s\n", sysconf(_SC_SEMAPHORES) ? "Yes" : "No" );
    
     mutex = sem_open(SEM_NAME, O_CREAT, 0666, 1);
    
     if (mutex == SEM_FAILED) printf("Failed %d\n", errno);
     else {
            puts("Success - pause while you check /dev/shm ");
            sleep(5);
            sem_close(mutex);
            sem_unlink(SEM_NAME);
     }
    }
    
  • Kieran Tully
    Kieran Tully over 15 years
    Thank you for your help - this would probably fix it on Slackware 11, but it turns out we are on Slackware 10. Upgrading the libraries / kernel is too risky on the live systems, so I'm looking into a code workaround.
  • Kieran Tully
    Kieran Tully over 15 years
    Thanks. Before I wrote my "answer" I verified that sem_init(pshared=0) can create unshared semaphores on the affected systems. I didn't test if unshared semaphores can be shared reliably across processes. The man page says they aren't suitable for sharing, so I wouldn't want to rely on them.