我有一段 C++ 代码,当我从 Linux 终端运行它时运行得很好,但是当从 SystemV (init.d) 脚本运行时它会抛出 EPERM 错误启动时。该错误来自 pthread_create,其中将以下属性分配给尝试创建的线程:
pthread_t reading_thread;
pthread_attr_t read_attr;
struct sched_param read_param;
pthread_attr_init(&read_attr);
pthread_attr_setschedpolicy(&read_attr, SCHED_FIFO);
pthread_attr_setinheritsched(&read_attr, PTHREAD_EXPLICIT_SCHED);
read_param.sched_priority = 30;
pthread_attr_setschedparam(&read_attr, &read_param);
k = pthread_create(&reading_thread, &read_attr, Reading_Thread_Function,
(void*) &variable_to_pass_to_Reading_Thread_Function); // Will return EPERM
当从我的终端运行时,这段代码工作得很好。当我调用“/etc/init.d/myinitdscript start”时,它在 init.d 脚本中也运行得很好。它也可以作为“sudo service myinitdscript start”正常运行。 init.d 脚本包含以下内容:
#! /bin/sh
### BEGIN INIT INFO
# Provides: myinitdscript
# Required-Start: $local_fs $remote_fs $syslog $network
# Required-Stop: $local_fs $remote_fs $syslog $network
# Default-Start: 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Starts my daemon
# Description: Verbose explanation of starting my daemon
### END INIT INFO
PATH=/sbin:/usr/sbin:/bin:/usr/bin
LOG=/home/someusershome/initd.log
NAME=myinitdscript
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
[ -x "$DAEMON" ] || (echo "$DAEMON not found. Exiting $SCRIPTNAME." >> $LOG 2>&1 && exit 0)
USERTORUNAS=a_user_on_my_system
SOURCE_SCRIPT=/home/$USERTORUNAS/source_script
DAEMON_ARGS="some_args_for_script"
. /lib/init/vars.sh
. /lib/lsb/init-functions
# Source this script for environmental variables
[ -f $SOURCE_SCRIPT ] && . $SOURCE_SCRIPT
# This is called when called with 'start', I am skipping that for succintness
do_start()
{
start-stop-daemon --start --make-pidfile --pidfile $PIDFILE --test --background --chuid $USERTORUNAS --startas /bin/bash -- -c "exec $DAEMON -- $DAEMON_ARGS >> $LOG 2>&1 " || return 1
start-stop-daemon --start --make-pidfile --pidfile $PIDFILE --background --chuid $USERTORUNAS --startas /bin/bash -- -c "exec $DAEMON -- $DAEMON_ARGS >> $LOG 2>&1" || return 2
}
如果我使用以下命令激活此 init.d 脚本:
update-rc.d myinitdscript defaults 99
它会在启动时出错,并在 pthread_create 调用(k = 1,又名 EPERM)时抛出 EPERM 错误。我可以使用 sudo service myinitdscript start 运行它,它会运行得很好。我还可以调用 /etc/init.d/myinitdscript start ,它会运行得很好。只有当我让系统在启动时运行此脚本时,它才会失败。
我发现,如果我添加到我的启动-停止守护进程调用选项“-P fifo:99”,我不会收到 EPERM 错误,并且代码运行正常,除非优先级太高,所以我不会将此称为使固定。代码中唯一需要实时运行的部分是从代码中创建的 pthread。所以我想这与我从正常调度的线程中创建优先级为 30 的实时线程的权限有关。
为什么我的脚本在从启动运行时需要特殊的调度策略/优先级,而不是手动启动 init.d 脚本或通过服务运行?
编辑:在 Ubuntu 12.04 上运行。
编辑2:我尝试在启动-停止守护进程调用启动的代码中添加对“ulimit -r”的调用,并且我得到了无限的限制,所以据我所知,SCHED_FIFO 不应该出现任何权限问题:30 那里
EDIT3:事实证明我正在运行 Upstart,Upstart 有一个名为 rc-sysinit.conf 的初始化脚本,它启动所有 SystemV 样式脚本。所以也许 Upstart 搞砸了我的权限。
答案1
答案似乎是将以下内容放入我的 init.d 脚本中,我将其放在 do_start 中的 start-stop-daemon 调用之前:
ulimit -r ## (where ## is a sufficiently high number; 99 works)
我能够确定这一点的方法是在代码中的 bash 命令内对 ulimit -a 进行系统调用:
bash -c "ulimit -a"
bash 部分是必要的,因为 ulimit -a 是 shell 内置命令。 /bin/sh 上的 ulimit -a 返回与实时优先级无关的不同信息。由于某种原因,我发现当我的服务在启动时启动时,我的实时优先级被限制为0(无实时优先级)。当我使用服务或调用 init.d 脚本运行它时,它会继承我的权限,从而实现实时优先级。但是,当系统通过 Upstart/SystemV 向后兼容系统调用它时,它不会获得提升的权限。我想这可能与我看到的帖子有关,这些帖子说 Upstart 不读取 /etc/security/limits.conf ,您可以在 /etc/security/limits.conf 中为非特权用户设置系统范围的实时优先级权限。
如果有人可以验证或解释为什么这个解决方案有效,我很想听听。