Linux

使用 init.d 從非實時執行緒創建的實時 pthread

  • October 11, 2016

我有一段 C++ 程式碼在我從 Linux 終端執行時執行良好,但在 bootup 上從 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,它會執行得很好。只有當我讓系統在啟動時執行此腳本時,它才會失敗。

我發現如果我添加到我的 start-stop-daemon 呼叫選項“-P fifo:99”我不會收到 EPERM 錯誤並且程式碼執行正常,除非優先級太高,所以我不會稱之為使固定。程式碼中唯一需要實時執行的部分是在程式碼中創建的 pthread。所以我想這與我在正常調度的執行緒中創建優先級為 30 的實時執行緒的權限有關。

為什麼我的腳本在從引導執行而不是手動啟動 init.d 腳本或通過服務執行時需要特殊的調度策略/優先級?

編輯:在 Ubuntu 12.04 上執行。

EDIT2:我嘗試在啟動-停止-守護程序呼叫開始的程式碼中添加對“ulimit -r”的呼叫,並且我得到無限,所以據我所見,SCHED_FIFO 不應該有任何權限問題:30 那裡

EDIT3:原來我正在執行 Upstart,Upstart 有一個名為 rc-sysinit.conf 的初始化腳本,它啟動所有 SystemV 樣式的腳本。所以也許新貴搞砸了我的權限。

答案似乎是將以下內容放在我的 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。ulimit -a on /bin/sh 返回與實時優先級無關的不同資訊。由於某種原因,我發現當我的服務在啟動時啟動時,我的實時優先級被限制為 0(無實時優先級)。當我使用服務或呼叫 init.d 腳本執行它時,它會繼承我允許實時優先級的權限。但是當系統通過 Upstart/SystemV 向後兼容系統呼叫它時,它並沒有獲得提升的特權。我想這可能與我看到的文章有關,說 Upstart 不讀取 /etc/security/limits.conf ,您可以在其中為非特權使用者設置系統範圍的實時優先級權限。

如果有人可以驗證或解釋為什麼這個解決方案有效,我很想听聽。

引用自:https://unix.stackexchange.com/questions/315068