【问题标题】:How do I stop sem_open() failing with ENOSYS?如何阻止 sem_open() 因 ENOSYS 失败?
【发布时间】:2010-09-21 04:06:24
【问题描述】:

我有两个 Slackware Linux 系统,POSIX 信号量 sem_open() 调用失败,errno 设置为 38。下面重现的示例代码(代码在 CentOS / RedHat 上运行良好)。

是否有任何内核或系统配置选项可能导致此问题?其他建议?

有问题的系统是 Slackware 10.1.0 内核 2.6.11 /lib/librt-2.3.4.so /lib/libpthread-0.10.so,但相同的代码适用于更旧的 RedHat 9 内核 2.4.20 / lib/librt-2.3.2.so /lib/tls/libpthread-0.29.so。 (也适用于 CentOS 5 内核 2.6.18 /lib/librt-2.5.so /lib/i686/nosegneg/libpthread-2.5.so)。

man sem_open 建议这个 errno 意味着系统不支持sem_open()

#define ENOSYS          38      /* Function not implemented */

sem_open() 用户空间位于我们动态链接的 librt 中,librt 存在于受影响的系统上。

受影响的系统声称支持 POSIX 信号量:_POSIX_SEMAPHORES 为真,sysconf(_SC_SEMAPHORES) 证实了这一点。

谢谢, 基兰

编辑 1:我添加了有关正在使用的软件版本的更多详细信息,并删除了一些不相关的 cmets。

编辑 2:/dev/shm 安装在好的系统上,而不是安装在坏的系统上。安装它并没有改变受影响系统上的行为。我认为 /dev/shm 也是必要的,但 sem_open() 在此之前失败了,strace 支持这一点。

# /* 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);
 }
}

【问题讨论】:

    标签: c linux ipc posix semaphore


    【解决方案1】:

    是否已安装 /dev/shm?旧版本的 slackware 可能没有在引导时挂载这个文件系统。来自 /etc/fstab:

    tmpfs  /dev/shm  tmpfs  defaults  0   0
    

    编辑:毕竟这可能不是问题。我认为您可能只需要升级内核甚至 librt。

    Edit2:我认为对于我认为您正在使用的 slackware 11,您需要一个比 2.6.13 更新的内核才能使用似乎需要的 NPTL 线程库(/lib/tls 中的库) sem_open 开始工作。

    Edit3:我设法让它与我拥有的 slackware 11 盒子一起工作,方法是 a)安装 /dev/shm 和 b)将环境变量 LD_ASSUME_KERNEL 设置为 2.6.13(任何内核版本 > 2.6.12 都会工作)。即使内核是 2.6.11.11,这似乎也可以工作,但线程等其他东西可能不会。

    【讨论】:

    • 感谢您的帮助 - 这可能会在 Slackware 11 上修复它,但事实证明我们在 Slackware 10 上。在实时系统上升级库/内核风险太大,所以我寻找代码解决方法。
    【解决方案2】:

    旧版本的线程库不支持在进程之间共享 POSIX 信号量。来自man sem_init

    pshared 参数指示信号量是否是本地的 当前进程( pshared 为零)或将在多个进程之间共享 进程( pshared 不为零)。 LinuxThreads 目前没有 支持进程共享信号量,因此 sem_init 总是返回 如果 pshared 不为零,则错误 ENOSYS。

    当 sem_open() 创建命名信号量时,它总是尝试在进程之间共享它们。

    支持在 Slackware 10 上使用 sem_init() 在进程之间共享匿名信号量

    • 升级 libpthread 和(可能)librt
    • 升级内核

    此外,支持与 sem_open() 共享命名信号量

    • /etc/fstab 中添加一行以将/dev/shm 挂载为tmpfs

      tmpfs /dev/shm tmpfs 默认值 0 0

    • 运行mount /dev/shm或重启

    【讨论】:

      【解决方案3】:

      “进程共享 sema4 不起作用”假设对我来说是有道理的。并不是说它对您有帮助,但如果您有时间和意愿,您可能想尝试以下方法,看看“进程共享”方面是否是失败的:

      1. 在非共享内存中使用 sem_init 创建一个信号量(用于线程)。如果它有效,那么 sema4s 将在进程中工作。

      2. 在共享内存中重复实验。这应该告诉您它们是否在进程之间工作。请注意,您可能需要实际尝试使用 sema4 来查看它是否在进程之间工作。

      【讨论】:

      • 谢谢。在我写下我的“答案”之前,我验证了sem_init(pshared=0) 可以在受影响的系统上创建非共享信号量。我没有测试是否可以跨进程可靠地共享未共享的信号量。手册页说它们不适合共享,所以我不想依赖它们。
      【解决方案4】:

      另一种跨进程共享信号量的方法是使用 SystemV 信号量。

      即使在共享 POSIX 信号量不起作用的情况下(至少在上述系统上),这些也确实有效。

      请参阅http://www.linuxdevcenter.com/pub/a/linux/2007/05/24/semaphores-in-linux.html,了解两种类型的信号量使用示例。

      【讨论】:

        【解决方案5】:

        我在使用 posix 消息队列时遇到了同样的错误 mq_open is failed with errono 38 (ENOSYS)。

        解决方法是在内核配置中启用 POSIX MESSGE QUEUE 来重建 kenel。

        这将构建具有 POSIX 消息队列支持的内核,它对我有用。

        谢谢

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-06
          • 1970-01-01
          • 2016-03-15
          • 2012-08-10
          • 2019-10-21
          • 2012-12-15
          相关资源
          最近更新 更多