使用 init.d 從非實時執行緒創建的實時 pthread
我有一段 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 ,您可以在其中為非特權使用者設置系統範圍的實時優先級權限。
如果有人可以驗證或解釋為什麼這個解決方案有效,我很想听聽。